import 'dart:async'; import 'package:flutter/material.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:intl/intl.dart'; import 'package:mobdr/main.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/events.dart'; import 'package:mobdr/model/visit_model.dart'; import 'package:mobdr/ui/reusable/cache_image_network.dart'; import 'package:mobdr/ui/sync/upload_photos.dart'; import 'package:mobdr/ui/sync/check_connection.dart'; import 'package:mobdr/ui/sync/synchronization.dart'; class SynchronizationPage2 extends StatefulWidget { @override _SynchronizationPage2State createState() => _SynchronizationPage2State(); } class _SynchronizationPage2State extends State { late List tosyncVisitData = []; bool isLoading = true; // _listKey is used for AnimatedList var _listKey = GlobalKey(); @override void initState() { super.initState(); loadData(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { final double boxImageSize = (MediaQuery.of(context).size.width / 4); return Scaffold( appBar: AppBar( iconTheme: IconThemeData( color: GlobalStyle.appBarIconThemeColor, ), elevation: GlobalStyle.appBarElevation, title: Text( 'Data synchronization', style: GlobalStyle.appBarTitle, ), backgroundColor: GlobalStyle.appBarBackgroundColor, systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle), body: isLoading ? Center( child: CircularProgressIndicator(), ) : Column( children: [ Container( padding: EdgeInsets.fromLTRB(16, 16, 16, 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Calendar', style: GlobalStyle.horizontalTitle), Row( children: [ Icon(Icons.refresh), Text(SharedPrefs().lastCalendarRefresh.isNotEmpty ? SharedPrefs().lastCalendarRefresh : "Never"), ], ), ], ), ), SizedBox(height: 8), // Ajout de l'espace ici TextButton( onPressed: () async { final result = await Navigator.push( context, MaterialPageRoute( //builder: (context) => SyncCalendarPage()), builder: (context) => SynchronizationPage2()), ); // Refresh the widget if the synchronization was successful. if (result == true) { SharedPrefs().lastCalendarRefresh = DateFormat('dd/MM/yyyy HH:mm').format(DateTime.now()); eventBus.fire(RefreshCalendarEvent( SharedPrefs().lastCalendarRefresh)); setState(() { loadData(); }); } else SharedPrefs().lastCalendarRefresh = ""; }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Synchronize', style: TextStyle( color: Colors.blue, fontSize: 16, fontWeight: FontWeight.bold, ), ), Icon(Icons.chevron_right, color: Colors.blue), ], ), ), Container( padding: EdgeInsets.fromLTRB(16, 16, 16, 0), child: Row( children: [ Text('Visits', style: GlobalStyle.horizontalTitle), ], ), ), if (tosyncVisitData.isEmpty) Container( padding: EdgeInsets.all(16), child: Text("You didn't take any photos..."), ), Flexible( child: AnimatedList( key: _listKey, initialItemCount: tosyncVisitData.length, physics: AlwaysScrollableScrollPhysics(), itemBuilder: (context, index, animation) { return Dismissible( key: UniqueKey(), direction: DismissDirection.endToStart, onDismissed: (direction) { // the photo must be removed setState(() { tosyncVisitData.removeAt(index); _listKey = GlobalKey(); }); }, background: Container( color: Colors.red, child: Stack( children: [ Positioned.fill( child: Align( alignment: Alignment.center, child: Icon( Icons.delete, color: Colors.white, ), ), ), ], ), ), child: _buildVisitlistCard(tosyncVisitData[index], boxImageSize, animation, index), ); }, ), ), Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey, offset: Offset(0.0, 1.0), //(x,y) blurRadius: 2.0, ), ], ), child: Row( children: [ Container( child: GestureDetector( onTap: () { // TODO filter functionality to be implemented (view deleted visits) /*` Navigator.push( context, MaterialPageRoute( builder: (context) => ChatUsPage())); */ }, child: ClipOval( child: Container( color: SOFT_BLUE, padding: EdgeInsets.all(9), child: Icon(Icons.filter_list, color: Colors.white, size: 16)), ), ), ), SizedBox( width: 10, ), Expanded( child: GestureDetector( onTap: tosyncVisitData.isNotEmpty ? () { navigateToPage(context, 0, 0); } : null, child: Container( alignment: Alignment.center, padding: EdgeInsets.fromLTRB(12, 8, 12, 8), margin: EdgeInsets.only(right: 8), decoration: BoxDecoration( color: Colors.white, border: Border.all( width: 1, color: tosyncVisitData.isNotEmpty ? Colors.red : Colors.grey), borderRadius: BorderRadius.all( Radius.circular(10), ), ), child: Text( 'Synchronize ALL visits', style: TextStyle( color: tosyncVisitData.isNotEmpty ? Colors.red : Colors.grey, fontWeight: FontWeight.bold, ), ), ), ), ), ], ), ), ], ), ); } Widget _buildVisitlistCard(VisitModel data, boxImageSize, animation, index) { return SizeTransition( sizeFactor: animation, child: Container( margin: EdgeInsets.fromLTRB(12, 6, 12, 0), child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), elevation: 2, color: Colors.white, child: Container( margin: EdgeInsets.all(8), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipRRect( borderRadius: BorderRadius.all(Radius.circular(10)), child: buildCacheNetworkImage( width: boxImageSize, height: boxImageSize, url: data.image, ), ), SizedBox( width: 10, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.only(top: 5), child: Row( children: [ Text(data.name, style: GlobalStyle.productPrice) ], ), ), Container(height: 8), Text( data.date, style: GlobalStyle.productSale, ), Container( margin: EdgeInsets.only(top: 5), child: Text( '${data.photoCount} Photo(s)', style: GlobalStyle.productPrice, ), ), Container(height: 8), Container( margin: EdgeInsets.only(top: 5), child: Row( children: [ Icon( Icons.store, color: SOFT_GREY, size: 20, ), Text( ' ' + data.type_visite, style: GlobalStyle.productName.copyWith( fontSize: 13, ), maxLines: 1, overflow: TextOverflow.ellipsis, ) ], ), ), ], ), ) ], ), Container( margin: EdgeInsets.only(top: 12), child: Row( children: [ Expanded( child: (data.photoCount == 0) ? TextButton( style: ButtonStyle( minimumSize: MaterialStateProperty.all(Size(0, 30)), backgroundColor: MaterialStateProperty.resolveWith( (Set states) => Colors.grey[300]!, ), overlayColor: MaterialStateProperty.all( Colors.transparent), shape: MaterialStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), )), ), onPressed: () {}, child: Text( 'Synchronize', style: TextStyle( color: Colors.grey[600], fontWeight: FontWeight.bold, fontSize: 13), textAlign: TextAlign.center, )) : OutlinedButton( onPressed: () { navigateToPage( context, index, data.id_visite); }, style: ButtonStyle( minimumSize: MaterialStateProperty.all(Size(0, 30)), overlayColor: MaterialStateProperty.all( Colors.transparent), shape: MaterialStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), )), side: MaterialStateProperty.all( BorderSide(color: SOFT_BLUE, width: 1.0), )), child: Text( 'Synchronize', style: TextStyle( color: SOFT_BLUE, fontWeight: FontWeight.bold, fontSize: 13), textAlign: TextAlign.center, )), ), ], ), ) ], ), ), ), ), ); } Future navigateToPage( BuildContext context, int index, int id_visite) async { var connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.none) { await Navigator.push( context, MaterialPageRoute( builder: (context) => CheckConnectionPage( redirectPage: UploadPhotosPage(pp_id_visite: id_visite), ), ), ); // the visit must be removed /* setState(() { tosyncVisitData.removeAt(index); _listKey = GlobalKey(); }); */ } else { await Navigator.push( context, MaterialPageRoute( builder: (context) => UploadPhotosPage(pp_id_visite: id_visite))); } /* setState(() { isLoading = true; // Mettez à jour l'état ici }); // remove all items int itemCount = tosyncVisitData.length; for (int i = itemCount - 1; i >= 0; i--) { tosyncVisitData.removeAt(i); _listKey.currentState!.removeItem( i, (context, animation) => Container()); // Remplacez Container() par le widget à animer lors de la suppression de l'élément } loadData(); */ } /// Initializes data when the page loads. Future loadData() async { // initialization of data with all visits to be synchronized tosyncVisitData = await VisitModel.getToSyncVisits(); setState(() { isLoading = false; }); } }