diff --git a/assets/images/synchro.png b/assets/images/synchro.png new file mode 100644 index 0000000..4e6c5f9 Binary files /dev/null and b/assets/images/synchro.png differ diff --git a/lib/config/global_style.dart b/lib/config/global_style.dart index 8ec2e87..d8c2502 100644 --- a/lib/config/global_style.dart +++ b/lib/config/global_style.dart @@ -178,7 +178,7 @@ class GlobalStyle { TextStyle(fontSize: 18, fontWeight: FontWeight.bold); static const TextStyle cardTitle = - TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold); + TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold); static const TextStyle textPromo = TextStyle( fontSize: 12, diff --git a/lib/model/visit_model.dart b/lib/model/visit_model.dart index d51e88d..cc955c4 100644 --- a/lib/model/visit_model.dart +++ b/lib/model/visit_model.dart @@ -12,18 +12,21 @@ class VisitModel { late String image; late String type_visite; late String langage; + late DateTime? date_validation; - VisitModel( - {required this.id, - required this.id_distrib, - required this.id_etab, - required this.id_visite, - required this.name, - required this.photoCount, - required this.date, - required this.image, - required this.type_visite, - required this.langage}); + VisitModel({ + required this.id, + required this.id_distrib, + required this.id_etab, + required this.id_visite, + required this.name, + required this.photoCount, + required this.date, + required this.image, + required this.type_visite, + required this.langage, + required this.date_validation, + }); static Future> getTodayVisits() async { // Retrieve all today visits from the database @@ -42,7 +45,8 @@ class VisitModel { .format(visite.date_visite), image: visite.url_photo_principale, type_visite: visite.type_visite, - langage: visite.langage)) + langage: visite.langage, + date_validation: visite.date_validation)) .toList(); // Return the list of VisiteModel @@ -66,16 +70,17 @@ class VisitModel { .format(visite.date_visite), image: visite.url_photo_principale, type_visite: visite.type_visite, - langage: visite.langage)) + langage: visite.langage, + date_validation: visite.date_validation)) .toList(); // Return the list of VisiteModel return visitModelList; } - static List getToSyncVisits() { + static Future> getToSyncVisits() async { // Retrieve all visits from the database - final visits = objectbox.getAllVisit(); + final visits = await objectbox.getAllVisit(); // Map each retrieved visit to VisiteModel final visitModelList = visits @@ -90,7 +95,8 @@ class VisitModel { .format(visite.date_visite), image: visite.url_photo_principale, type_visite: visite.type_visite, - langage: visite.langage)) + langage: visite.langage, + date_validation: visite.date_validation)) .where((visit) => visit.photoCount > 0) // Filter out visits with photoCount equal to 0 diff --git a/lib/objectbox.dart b/lib/objectbox.dart index 34aef1b..038e302 100644 --- a/lib/objectbox.dart +++ b/lib/objectbox.dart @@ -78,9 +78,6 @@ class ObjectBox { .map((query) => query.find()); } - static void _putNotesInTx(Store store, List notes) => - store.box().putMany(notes); - /// Add a note within a transaction. /// /// To avoid frame drops, run ObjectBox operations that take longer than a diff --git a/lib/old/tab_sync.dart b/lib/old/tab_sync.dart index 43a5307..0b881c7 100644 --- a/lib/old/tab_sync.dart +++ b/lib/old/tab_sync.dart @@ -6,7 +6,6 @@ import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/ui/reusable/reusable_widget.dart'; import 'package:mobdr/network/api_provider.dart'; import 'package:mobdr/main.dart'; -import 'package:mobdr/ui/home/tab_home.dart'; const completeColor = Color(0xff5e6172); const inProgressColor = Color(0xff5ec792); diff --git a/lib/ui/home.dart b/lib/ui/home.dart index f7c0f19..210418d 100644 --- a/lib/ui/home.dart +++ b/lib/ui/home.dart @@ -77,38 +77,44 @@ class _HomePageState extends State type: BottomNavigationBarType.fixed, currentIndex: _currentIndex, onTap: (value) { - _currentIndex = value; - _pageController.jumpToPage(value); - // this unfocus is to prevent show keyboard in the wishlist page when focus on search text field - FocusScope.of(context).unfocus(); + setState(() { + _currentIndex = value; + _pageController.jumpToPage(value); + FocusScope.of(context).unfocus(); + }); }, selectedFontSize: 8, unselectedFontSize: 8, iconSize: 28, + selectedItemColor: + Colors.blue, // Couleur de l'icône de l'onglet sélectionné + unselectedItemColor: + CHARCOAL, // Couleur de l'icône des onglets non sélectionnés selectedLabelStyle: TextStyle( - color: _currentIndex == 1 ? ASSENT_COLOR : PRIMARY_COLOR, - fontWeight: FontWeight.bold), - unselectedLabelStyle: - TextStyle(color: CHARCOAL, fontWeight: FontWeight.bold), - selectedItemColor: _currentIndex == 1 ? ASSENT_COLOR : PRIMARY_COLOR, - unselectedItemColor: CHARCOAL, + color: Colors.blue, // Couleur du texte de l'onglet sélectionné + fontWeight: FontWeight.bold, + ), + unselectedLabelStyle: TextStyle( + color: CHARCOAL, // Couleur du texte des onglets non sélectionnés + fontWeight: FontWeight.bold, + ), items: [ BottomNavigationBarItem( - label: 'Home', - icon: Icon(Icons.home, - color: _currentIndex == 0 ? PRIMARY_COLOR : CHARCOAL)), + label: 'Home', + icon: Icon(Icons.home), + ), BottomNavigationBarItem( - label: 'Synchro', - icon: Icon(Icons.sync, - color: _currentIndex == 1 ? ASSENT_COLOR : CHARCOAL)), + label: 'Synchro', + icon: Icon(Icons.sync), + ), BottomNavigationBarItem( - label: 'MP4', - icon: Icon(Icons.web, - color: _currentIndex == 2 ? PRIMARY_COLOR : CHARCOAL)), + label: 'MP4', + icon: Icon(Icons.web), + ), BottomNavigationBarItem( - label: 'Account', - icon: Icon(Icons.person_outline, - color: _currentIndex == 3 ? PRIMARY_COLOR : CHARCOAL)), + label: 'Account', + icon: Icon(Icons.person_outline), + ), ], ), ); diff --git a/lib/ui/home/tab_home.dart b/lib/ui/home/tab_home.dart index 47b775b..c422cb4 100644 --- a/lib/ui/home/tab_home.dart +++ b/lib/ui/home/tab_home.dart @@ -18,7 +18,7 @@ import 'package:mobdr/cubit/language/app_localizations.dart'; import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/events.dart'; -import 'package:mobdr/ui/sync/sync_calendar.dart'; +import 'package:mobdr/ui/sync/synchronization.dart'; import 'package:mobdr/model/visit_model.dart'; import 'package:mobdr/ui/visit/visit_photo_typology.dart'; import 'package:mobdr/ui/general/chat_us.dart'; @@ -188,7 +188,7 @@ class _TabHomePageState extends State return Column( children: [ Container( - padding: EdgeInsets.fromLTRB(16, 16, 16, 0), + padding: EdgeInsets.fromLTRB(16, 8, 0, 0), child: Row( children: [ Text('Last visit access', style: GlobalStyle.horizontalTitle), @@ -197,10 +197,9 @@ class _TabHomePageState extends State ), Container( margin: EdgeInsets.only(top: 8), - height: boxImageSize * GlobalStyle.cardHeightMultiplication, alignment: Alignment.centerLeft, padding: EdgeInsets.symmetric(horizontal: 12), - child: buildHorizontalVisitListCard(context, lastVisitData)), + child: buildVisitListCard(context, lastVisitData!)), ], ); } @@ -238,13 +237,12 @@ class _TabHomePageState extends State Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox(height: 16), // Ajout de l'espace ici - Text('Aucune visite ce jour'), - ElevatedButton( + TextButton( onPressed: () async { final result = await Navigator.push( context, - MaterialPageRoute(builder: (context) => SyncCalendarPage()), + MaterialPageRoute( + builder: (context) => SynchronizationPage()), ); // Refresh the widget if the synchronization was successful. @@ -254,7 +252,20 @@ class _TabHomePageState extends State }); } }, - child: Text('Synchroniser'), + 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), + ], + ), ), ], ) @@ -308,7 +319,100 @@ class _TabHomePageState extends State ); } - Widget buildHorizontalVisitListCard(context, data) { + Widget buildVisitListCard(BuildContext context, VisitModel data) { + final double boxImageSize = (MediaQuery.of(context).size.width / 4); + return GestureDetector( + onTap: () { + Route route = MaterialPageRoute( + builder: (context) => VisitPhotoTypologyPage(pp_visitModel: data), + ); + Navigator.push(context, route); + }, + child: Container( + margin: EdgeInsets.fromLTRB(0, 0, 0, 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, + ), + ], + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } + + Widget buildHorizontalVisitListCard(context, VisitModel data) { final double imageWidth = (MediaQuery.of(context).size.width / 2.3); final double imageheight = (MediaQuery.of(context).size.width / 3.07); @@ -364,9 +468,15 @@ class _TabHomePageState extends State right: 4, // alignement à droite child: GestureDetector( onTap: () { - // TODO si visite validée ce n'est pas la meme url (on il mettre date validation dans le json frederik - SharedPrefs().urlMP4 = - '${ApiConstants.baseUrl}/MobilePortal4/index.html#ajax/visite_modification.html?visite=${data.id_visite}'; + // TODO: si visite validée ce n'est pas la meme url + if (data.date_validation == null) { + SharedPrefs().urlMP4 = + '${ApiConstants.baseUrl}/MobilePortal4/index.html#ajax/visite_modification.html?visite=${data.id_visite}'; + } else { + SharedPrefs().urlMP4 = + '${ApiConstants.baseUrl}/MobilePortal4/index.html#ajax/visite_modification.html?visite=${data.id_visite}'; + } + eventBus.fire(UrlEvent(SharedPrefs().urlMP4)); }, child: Image.asset( @@ -389,7 +499,10 @@ class _TabHomePageState extends State ), badgeContent: Text(data.photoCount.toString(), style: TextStyle(color: Colors.white)), - child: Icon(Icons.camera_alt_sharp), + child: Icon( + Icons.camera_alt_sharp, + color: Colors.grey, + ), ), ), ), diff --git a/lib/ui/sync/sync_calendar.dart b/lib/ui/sync/sync_calendar copy.dart similarity index 94% rename from lib/ui/sync/sync_calendar.dart rename to lib/ui/sync/sync_calendar copy.dart index 3caf655..7469812 100644 --- a/lib/ui/sync/sync_calendar.dart +++ b/lib/ui/sync/sync_calendar copy.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:mobdr/network/api_provider.dart'; -class SyncCalendarPage extends StatefulWidget { +class SyncCalendarPage2 extends StatefulWidget { @override - _SyncCalendarPageState createState() => _SyncCalendarPageState(); + _SyncCalendarPage2State createState() => _SyncCalendarPage2State(); } -class _SyncCalendarPageState extends State { +class _SyncCalendarPage2State extends State { bool _isSyncing = false; bool _syncSuccessful = false; String? _syncErrorMessage; diff --git a/lib/ui/sync/synchronization copy.dart b/lib/ui/sync/synchronization copy.dart new file mode 100644 index 0000000..08c1d46 --- /dev/null +++ b/lib/ui/sync/synchronization copy.dart @@ -0,0 +1,451 @@ +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; + }); + } +} diff --git a/lib/ui/sync/synchronization.dart b/lib/ui/sync/synchronization.dart index ae126fd..ea4512b 100644 --- a/lib/ui/sync/synchronization.dart +++ b/lib/ui/sync/synchronization.dart @@ -1,400 +1,211 @@ -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/sync_calendar.dart'; - -class SynchronizationPage extends StatefulWidget { - @override - _SynchronizationPageState createState() => _SynchronizationPageState(); -} - -class _SynchronizationPageState extends State { - late List tosyncVisitData = []; - - // _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: 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 - ElevatedButton( - onPressed: () async { - final result = await Navigator.push( - context, - MaterialPageRoute(builder: (context) => SyncCalendarPage()), - ); - - // 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: Text('Synchroniser'), - ), - 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 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: tosyncVisitData.isNotEmpty - ? () { - navigateToPage(context, 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, 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. - void loadData() { - // initialization of data with all visits to be synchronized - tosyncVisitData = VisitModel.getToSyncVisits(); - } -} +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:mobdr/service/shared_prefs.dart'; + +class SynchronizationPage extends StatefulWidget { + @override + _SynchronizationPageState createState() => _SynchronizationPageState(); +} + +class _SynchronizationPageState extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _rotationAnimation; + + bool _isSyncing = false; + bool _syncCompleted = false; + bool _backofficeSyncCompleted = false; + bool _photosSyncCompleted = false; + bool _logSyncCompleted = false; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + vsync: this, + duration: Duration(seconds: 2), + ); + _rotationAnimation = + Tween(begin: 0, end: 1).animate(_animationController); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + void startSync() { + setState(() { + _isSyncing = true; + _syncCompleted = false; + _backofficeSyncCompleted = false; + _photosSyncCompleted = false; + _logSyncCompleted = false; + }); + + _animationController.repeat(); + + // Simulation d'une tâche de synchronisation + Future.delayed(const Duration(seconds: 3), () { + SharedPrefs().lastCalendarRefresh = + DateFormat('dd/MM/yyyy HH:mm').format(DateTime.now()); + setState(() { + _isSyncing = false; + _syncCompleted = true; + _backofficeSyncCompleted = true; + _photosSyncCompleted = false; + _logSyncCompleted = false; + }); + _animationController.stop(); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Data synchronization'), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: 20), + Center( + child: Container( + width: 100, + height: 100, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.blue, + ), + child: IconButton( + icon: AnimatedBuilder( + animation: _animationController, + builder: (BuildContext context, Widget? child) { + return Transform.rotate( + angle: _rotationAnimation.value * 2.0 * 3.14, + child: Icon( + Icons.refresh, + color: Colors.white, + size: 80, + ), + ); + }, + ), + onPressed: _isSyncing ? null : startSync, + ), + ), + ), + SizedBox(height: 20), + Text( + SharedPrefs().lastCalendarRefresh.isNotEmpty + ? SharedPrefs().lastCalendarRefresh + : "Never", + style: TextStyle(fontSize: 16), + textAlign: TextAlign.center, + ), + SizedBox(height: 40), + SyncItem( + icon: Icons.business, + title: 'Backoffice', + description: 'Synchronisation des données du backoffice', + isSyncing: _isSyncing, + syncCompleted: _syncCompleted, + isError: _syncCompleted && !_backofficeSyncCompleted, + ), + SizedBox(height: 20), + SyncItem( + icon: Icons.photo, + title: 'Photos', + description: 'Synchronisation des photos', + isSyncing: _isSyncing, + syncCompleted: _syncCompleted, + isError: _syncCompleted && !_photosSyncCompleted, + ), + SizedBox(height: 20), + SyncItem( + icon: Icons.warning, + title: 'Log', + description: 'Synchronisation des journaux d\'activité', + isSyncing: _isSyncing, + syncCompleted: _syncCompleted, + isError: _syncCompleted && !_logSyncCompleted, + ), + ], + ), + ), + ); + } +} + +class SyncItem extends StatelessWidget { + final IconData icon; + final String title; + final String description; + final bool isSyncing; + final bool syncCompleted; + final bool isError; + + const SyncItem({ + required this.icon, + required this.title, + required this.description, + required this.isSyncing, + required this.syncCompleted, + required this.isError, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + icon, + color: Colors.blue, + size: 24, + ), + SizedBox(width: 10), + Text( + title, + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + ], + ), + SizedBox(height: 10), + Text(description), + SizedBox(height: 10), + if (isSyncing) + LinearProgressIndicator( + backgroundColor: Colors.grey[300], + valueColor: AlwaysStoppedAnimation(Colors.blue), + ), + if (syncCompleted) + Row( + children: [ + Icon( + isError ? Icons.error_outline : Icons.check, + color: isError ? Colors.red : Colors.green, + size: 20, + ), + SizedBox(width: 10), + Text( + isError + ? 'Erreur de synchronisation' + : 'Synchronisation terminée', + style: TextStyle( + color: isError ? Colors.red : Colors.green, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ], + ); + } +} diff --git a/lib/ui/sync/testsync copy.dart b/lib/ui/sync/testsync copy.dart new file mode 100644 index 0000000..45a04d9 --- /dev/null +++ b/lib/ui/sync/testsync copy.dart @@ -0,0 +1,228 @@ +import 'package:flutter/material.dart'; + +import 'package:mobdr/service/shared_prefs.dart'; +import 'package:mobdr/config/global_style.dart'; + +class SyncPage extends StatefulWidget { + @override + _SyncPageState createState() => _SyncPageState(); +} + +class _SyncPageState extends State + with SingleTickerProviderStateMixin { + AnimationController? _animationController; + late Animation _rotationAnimation; + + bool _isSyncing = false; + bool _syncCompleted = false; + + @override + void initState() { + super.initState(); + + _animationController = AnimationController( + duration: const Duration(seconds: 2), + vsync: this, + ); + + _rotationAnimation = Tween( + begin: 0, + end: 1, + ).animate(_animationController!); + + _animationController!.addStatusListener((status) { + if (status == AnimationStatus.completed) { + setState(() { + _syncCompleted = true; + }); + } + }); + + // Lancement automatique de la synchronisation au démarrage + //startSync(); + } + + @override + void dispose() { + _animationController!.dispose(); + super.dispose(); + } + + void startSync() { + setState(() { + _isSyncing = true; + _syncCompleted = false; + }); + + _animationController!.repeat(); + + // Simulation d'une tâche de synchronisation + Future.delayed(const Duration(seconds: 3), () { + setState(() { + _isSyncing = false; + _syncCompleted = true; + }); + _animationController!.stop(); + }); + } + + @override + Widget build(BuildContext context) { + final double screenWidth = MediaQuery.of(context).size.width; + final double screenHeight = MediaQuery.of(context).size.height; + + // Calcul du positionnement du premier cercle + final double circleSize = 55; + final double circleLeft = (screenWidth - circleSize) / 2 - 23; + final double circleTop = (screenHeight - circleSize) / 2 + 30; + + // Calcul du positionnement du deuxième cercle + final double secondCircleSize = 29; + final double secondCircleLeft = (screenWidth - circleSize) / 2 + 142; + final double secondCircleTop = (screenHeight - circleSize) / 2 + 75; + + // Définition de la couleur du premier cercle en fonction de l'état de synchronisation + Color circleColor; + if (_isSyncing) { + circleColor = Colors.lightBlue; + } else if (_syncCompleted) { + circleColor = Colors.green; + } else { + circleColor = Colors.transparent; + } + + return Scaffold( + appBar: AppBar( + title: Text('Page de synchronisation'), + ), + body: Stack( + children: [ + Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/synchro.png'), + fit: BoxFit.contain, + ), + ), + ), + 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"), + ], + ), + ], + ), + ), + if (_isSyncing || _syncCompleted) + Positioned( + left: circleLeft, + top: circleTop, + child: Container( + width: circleSize, + height: circleSize, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: circleColor, + ), + child: _syncCompleted + ? Icon( + Icons.check, + color: Colors.white, + size: circleSize - 20, + ) + : null, + ), + ), + if (_isSyncing || _syncCompleted) + Positioned( + left: secondCircleLeft, + top: secondCircleTop, + child: Container( + width: secondCircleSize, + height: secondCircleSize, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: circleColor, + ), + child: _syncCompleted + ? Icon( + Icons.check, + color: Colors.white, + size: secondCircleSize - 15, + ) + : null, + ), + ), + if (_isSyncing) + Positioned( + left: circleLeft + (circleSize - 70) / 2, + top: circleTop + (circleSize - 70) / 2, + child: Align( + alignment: Alignment.center, + child: AnimatedBuilder( + animation: _animationController!, + builder: (BuildContext context, Widget? child) { + return Transform.rotate( + angle: _rotationAnimation.value * 2.0 * 3.14, + child: Icon( + Icons.refresh, + color: Colors.white, + size: 70, + ), + ); + }, + ), + ), + ), + if (_isSyncing) + Positioned( + left: secondCircleLeft + (secondCircleSize - 35) / 2, + top: secondCircleTop + (secondCircleSize - 34) / 2, + child: AnimatedBuilder( + animation: _animationController!, + builder: (BuildContext context, Widget? child) { + return Transform.rotate( + angle: _rotationAnimation.value * 2.0 * 3.14, + child: Icon( + Icons.refresh, + color: Colors.white, + size: 35, + ), + ); + }, + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox(height: 20), + if (_isSyncing) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: LinearProgressIndicator(), + ), + SizedBox(height: 20), + ElevatedButton( + onPressed: _isSyncing ? null : startSync, + child: Text('Lancer la synchronisation'), + ), + SizedBox(height: 20), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/sync/upload_photos.dart b/lib/ui/sync/upload_photos.dart index c6a5002..1d2eb2e 100644 --- a/lib/ui/sync/upload_photos.dart +++ b/lib/ui/sync/upload_photos.dart @@ -5,6 +5,7 @@ import 'package:mobdr/main.dart'; import 'package:mobdr/events.dart'; import 'package:mobdr/db/box_visit_photo.dart'; import 'package:mobdr/network/api_provider.dart'; +import 'package:mobdr/service/shared_prefs.dart'; class UploadPhotosPage extends StatefulWidget { final int pp_id_visite; @@ -16,12 +17,12 @@ class UploadPhotosPage extends StatefulWidget { } class _UploadPhotosPageState extends State { - bool _isUploading = false; - bool _isFinished = false; + bool _isSyncing = false; + bool _syncSuccessful = false; int _totalUploaded = 0; int _totalPhotos = 0; - late List _photosList; + late List _visitPhotosList; ApiProvider _apiProvider = ApiProvider(); @@ -29,25 +30,17 @@ class _UploadPhotosPageState extends State { void initState() { super.initState(); - // "visit" mode - if (widget.pp_id_visite > 0) { - _photosList = objectbox.getAllVisitPhotosByVisit(widget.pp_id_visite); - _totalPhotos = _photosList.length; - // "all" mode - } else { - _photosList = objectbox.getAllVisitPhotos(); - _totalPhotos = _photosList.length; - } + loadData(); } - void _uploadPhotos() async { + Future _uploadVisitPhotos() async { setState(() { - _isUploading = true; - _isFinished = false; + _isSyncing = true; + _syncSuccessful = false; }); // parse all photos - for (var photo in _photosList) { + for (var photo in _visitPhotosList) { int id_photo_mp4 = -1; bool isUpdatePhotoTypologie = true; bool isUpdatePhotoVisibility = true; @@ -119,7 +112,8 @@ class _UploadPhotosPageState extends State { } // Get unique id_visite values from _photosList - Set uniqueIds = _photosList.map((photo) => photo.id_visite).toSet(); + Set uniqueIds = + _visitPhotosList.map((photo) => photo.id_visite).toSet(); // Send VisitPhotoCountEvent for each unique id_visite for (int id_visite in uniqueIds) { @@ -128,11 +122,45 @@ class _UploadPhotosPageState extends State { } setState(() { - _isUploading = false; - _isFinished = true; + _isSyncing = false; + _syncSuccessful = true; }); } + Future _clearVisitPhotoCache() async { + List _visitPhotoListTokeep; + Directory photosDir = Directory(SharedPrefs().photosDir); + + _visitPhotoListTokeep = objectbox.getAllVisitPhotos(); + + // Get a list of all files in the "photos" directory + final List files = await photosDir.list().toList(); + + // Check each file in the directory + for (FileSystemEntity file in files) { + if (file is File) { + // Extract the file name from the file path + String fileName = file.path.split('/').last; + + // Check if the file exists in the _visitPhotoListTokeep + bool existsInList = _visitPhotoListTokeep + .any((visitPhoto) => visitPhoto.image_name == fileName); + + if (!existsInList) { + // Delete the file if it doesn't exist in the _visitPhotoListTokeep + await file.delete(); + print('Deleted file: $fileName'); + } + } + } + } + + void _popScreen() { + if (mounted) { + Navigator.of(context).pop(_syncSuccessful); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -160,7 +188,7 @@ class _UploadPhotosPageState extends State { children: [ Center( child: Visibility( - visible: _isUploading, + visible: _isSyncing, child: Container( height: 150, width: 150, @@ -175,7 +203,7 @@ class _UploadPhotosPageState extends State { ), Center( child: Visibility( - visible: !_isUploading && _totalUploaded == _totalPhotos, + visible: !_isSyncing && _totalUploaded == _totalPhotos, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -195,7 +223,7 @@ class _UploadPhotosPageState extends State { ), Center( child: Visibility( - visible: !_isUploading && _totalUploaded != _totalPhotos, + visible: !_isSyncing && _totalUploaded != _totalPhotos, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -216,17 +244,36 @@ class _UploadPhotosPageState extends State { ], ), ), + if (_syncSuccessful) + Column( + children: [ + Icon(Icons.check_circle, size: 100.0, color: Colors.green), + SizedBox(height: 16.0), + ElevatedButton( + onPressed: _popScreen, + child: Text('Synchronisation réussie'), + ), + ], + ), SizedBox(height: 16), Visibility( - visible: !_isUploading, + visible: !_isSyncing, child: ElevatedButton( child: Text('Upload Photos ($_totalUploaded / $_totalPhotos)'), - onPressed: _isFinished + onPressed: _syncSuccessful ? null - : () { - _uploadPhotos(); + : () async { + // upload photo to server + await _uploadVisitPhotos(); + + // deletes photos that are no longer in any visits + await _clearVisitPhotoCache(); + + // go back + Navigator.pop(context); } + //, ), ), @@ -235,4 +282,18 @@ class _UploadPhotosPageState extends State { ), ); } + + /// Initializes data when the page loads. + void loadData() { + // "visit" mode + if (widget.pp_id_visite > 0) { + _visitPhotosList = + objectbox.getAllVisitPhotosByVisit(widget.pp_id_visite); + _totalPhotos = _visitPhotosList.length; + // "all" mode + } else { + _visitPhotosList = objectbox.getAllVisitPhotos(); + _totalPhotos = _visitPhotosList.length; + } + } } diff --git a/lib/ui/visit/visit_photo_typology_list.dart b/lib/ui/visit/visit_photo_typology_list.dart index 583010d..51d154f 100644 --- a/lib/ui/visit/visit_photo_typology_list.dart +++ b/lib/ui/visit/visit_photo_typology_list.dart @@ -140,11 +140,6 @@ class _VisitPhotoTypologyListPageState child: GestureDetector( onTap: () { ImportImageFromGallery(); - /*Navigator.push( - context, - MaterialPageRoute( - builder: (context) => PhotoPickPage())); - */ }, child: ClipOval( child: Container( diff --git a/pubspec.yaml b/pubspec.yaml index a019ecd..aafa676 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -162,6 +162,7 @@ flutter: - assets/images/logo_dark.png - assets/images/logo_mp4.png - assets/images/logo_horizontal.png + - assets/images/synchro.png - assets/images/onboarding/search_product.gif - assets/images/process_timeline/status1.png - assets/images/process_timeline/status2.png