import 'dart:async'; import 'package:flutter/material.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:mobdr/main.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/events.dart'; import 'package:mobdr/model/visit_model.dart'; import 'package:mobdr/ui/visit/visit_photo_typology.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'; class TabSyncPage extends StatefulWidget { @override _TabSyncPageState createState() => _TabSyncPageState(); } class _TabSyncPageState extends State with AutomaticKeepAliveClientMixin { // keep the state to do not refresh when switch navbar @override bool get wantKeepAlive => true; bool _isLoading = true; String _errorMessage = ''; late List tosyncVisitData = []; late StreamSubscription subVisitPhotoCountEvent; // _listKey is used for AnimatedList var _listKey = GlobalKey(); @override void initState() { super.initState(); // Listen particular event subVisitPhotoCountEvent = eventBus.on().listen((e) { setState(() { for (int i = 0; i < tosyncVisitData.length; i++) { if (tosyncVisitData[i].id_visite == e.id_visite) { tosyncVisitData[i].photoCount = e.photoCount; break; } } }); }); loadData().then((_) { setState(() { _isLoading = false; }); }); } @override void dispose() { subVisitPhotoCountEvent.cancel(); super.dispose(); } @override Widget build(BuildContext context) { // if we used AutomaticKeepAliveClientMixin, we must call super.build(context); super.build(context); final double boxImageSize = (MediaQuery.of(context).size.width / 4); if (_isLoading) { return Center(child: CircularProgressIndicator()); } else if (tosyncVisitData.isEmpty) { return Center( child: Text('No visits to synchronise.'), ); } return Scaffold( appBar: AppBar( iconTheme: IconThemeData( color: GlobalStyle.appBarIconThemeColor, ), elevation: GlobalStyle.appBarElevation, title: Text( 'Synchronization', style: GlobalStyle.appBarTitle, ), backgroundColor: GlobalStyle.appBarBackgroundColor, systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle), body: Column( children: [ 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: _buildVisitelistCard( 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 functionality to be implemented /*` 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: () { navigateToPage(context, 0); }, 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: Colors.red), borderRadius: BorderRadius.all( Radius.circular(10), )), child: Text( 'Synchronize ALL visits', style: TextStyle( color: Colors.red, fontWeight: FontWeight.bold), ), ), ), ), ], ), ), ], ), ); } Widget _buildVisitelistCard(VisitModel data, boxImageSize, animation, index) { return SizeTransition( sizeFactor: animation, child: GestureDetector( onTap: () { Route route = MaterialPageRoute( builder: (context) => VisitPhotoTypologyPage(pp_visitModel: data)); Navigator.push(context, route); }, 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, 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 id_visite) async { var connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.none) { Navigator.push( context, MaterialPageRoute( builder: (_) => CheckConnectionPage( redirectPage: UploadPhotosPage(pp_id_visite: id_visite), ), ), ); } else { Navigator.push( context, MaterialPageRoute( builder: (_) => UploadPhotosPage(pp_id_visite: id_visite))); } } /// Initializes data when the page loads. Future loadData() async { try { // initialization of data with all visits to be synchronized tosyncVisitData = await VisitModel.getToSyncVisits(); } catch (e) { // set errorMessage for debug _errorMessage = 'Error loading visits : $e'; } } }