import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../application/sync/sync_bloc.dart'; import '../../../common/extension/extension.dart'; import '../../../common/theme/theme.dart'; import '../../../injection.dart'; import '../../components/button/button.dart'; import '../../components/spaces/space.dart'; import '../../router/app_router.gr.dart'; import 'widgets/sync_completed.dart'; import 'widgets/sync_initial.dart'; import 'widgets/sync_state.dart'; @RoutePage() class SyncPage extends StatefulWidget implements AutoRouteWrapper { const SyncPage({super.key}); @override State createState() => _SyncPageState(); @override Widget wrappedRoute(BuildContext context) => BlocProvider(create: (context) => getIt(), child: this); } class _SyncPageState extends State with TickerProviderStateMixin { late AnimationController _animationController; late Animation _progressAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: Duration(milliseconds: 500), vsync: this, ); _progressAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.background, body: SafeArea( child: BlocConsumer( listener: (context, state) { // Kalau lagi syncing, update progress animasi if (state.isSyncing) { _animationController.animateTo(state.progress); } // Kalau sudah selesai sukses else if (state.stats != null && state.errorMessage == null) { _animationController.animateTo(1.0); // Tunggu sebentar lalu pindah ke dashboard // Future.delayed(const Duration(seconds: 2), () { // context.pushReplacement(DashboardPage()); // }); } // Kalau error else if (state.errorMessage != null) { _animationController.stop(); } }, builder: (context, state) { return Padding( padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16), child: Row( children: [ Expanded( flex: 2, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildHeader(), SizedBox(height: 20), _buildActions(state), ], ), ), SpaceWidth(40), SizedBox(width: 40), Expanded( flex: 3, child: SizedBox( height: context.deviceHeight * 0.8, child: Builder( builder: (context) { // Kondisi 1: error if (state.errorMessage != null) { return _buildErrorState(state.errorMessage!); } // Kondisi 2: sudah selesai if (state.stats != null) { return SyncCompletedWidget(stats: state.stats!); } // Kondisi 3: sedang syncing if (state.isSyncing) { return SyncStateWidget( step: state.currentStep ?? SyncStep.categories, progress: state.progress, message: state.errorMessage ?? '', progressAnimation: _progressAnimation, ); } // Kondisi default: initial return SyncInitialWidget(); }, ), ), ), ], ), ); }, ), ), ); } Widget _buildErrorState(String message) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error_outline, size: 48, color: Colors.red.shade400), SizedBox(height: 12), Text( 'Sinkronisasi Gagal', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.red.shade600, ), ), SizedBox(height: 8), Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(8), ), child: Text( message, style: TextStyle(fontSize: 12, color: Colors.red.shade700), textAlign: TextAlign.center, ), ), SizedBox(height: 12), Text( 'Periksa koneksi internet dan coba lagi', style: TextStyle(fontSize: 12, color: Colors.grey.shade600), textAlign: TextAlign.center, ), ], ); } Widget _buildHeader() { return Column( children: [ Container( width: 60, height: 60, decoration: BoxDecoration( color: AppColor.primary.withOpacity(0.1), borderRadius: BorderRadius.circular(15), ), child: Icon(Icons.sync, size: 30, color: AppColor.primary), ), SizedBox(height: 12), Text( 'Sinkronisasi Data', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.grey.shade800, ), ), SizedBox(height: 8), Text( 'Mengunduh kategori dan produk terbaru', style: TextStyle(fontSize: 16, color: Colors.grey.shade600), textAlign: TextAlign.center, ), ], ); } Widget _buildActions(SyncState state) { if (state.isSyncing) { return AppElevatedButton.outlined( onPressed: () { context.read().add(const SyncEvent.cancelSync()); }, label: 'Batalkan', ); } // Completed state if (state.stats != null && state.errorMessage == null) { return AppElevatedButton.filled( onPressed: () { context.router.replace(MainRoute()); }, label: 'Lanjutkan ke Aplikasi', ); } // Error state if (state.errorMessage != null) { return Row( children: [ Expanded( child: AppElevatedButton.outlined( onPressed: () { context.router.replace(MainRoute()); }, label: 'Lewati', ), ), const SizedBox(width: 16), Expanded( child: AppElevatedButton.filled( onPressed: () { context.read().add(const SyncEvent.startSync()); }, label: 'Coba Lagi', ), ), ], ); } // Default (initial) return AppElevatedButton.filled( onPressed: () { context.read().add(const SyncEvent.startSync()); }, label: 'Mulai Sinkronisasi', ); } }