import 'dart:async'; import 'package:flutter/material.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/visite_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'; class TabVisitListPage extends StatefulWidget { @override _TabVisitListPageState createState() => _TabVisitListPageState(); } class _TabVisitListPageState extends State with AutomaticKeepAliveClientMixin { // _listKey is used for AnimatedList final GlobalKey _listKey = GlobalKey(); // keep the state to do not refresh when switch navbar @override bool get wantKeepAlive => true; bool _isLoading = true; String _errorMessage = ''; late List modelData = []; late StreamSubscription subVisitPhotoCountEvent; @override void initState() { super.initState(); // Listen particular event subVisitPhotoCountEvent = eventBus.on().listen((e) { setState(() { for (int i = 0; i < modelData.length; i++) { if (modelData[i].id_visite == e.id_visite) { modelData[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 (modelData.isEmpty) { return Center( child: Text('No visits to synchronise.'), ); } return Scaffold( appBar: AppBar( iconTheme: IconThemeData( color: GlobalStyle.appBarIconThemeColor, ), elevation: GlobalStyle.appBarElevation, title: Text( 'Visit List', style: GlobalStyle.appBarTitle, ), backgroundColor: GlobalStyle.appBarBackgroundColor, systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle), body: Column(children: [ Flexible( child: AnimatedList( key: _listKey, initialItemCount: modelData.length, physics: AlwaysScrollableScrollPhysics(), itemBuilder: (context, index, animation) { return _buildVisitelistCard( modelData[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: () {}, 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: SOFT_BLUE), borderRadius: BorderRadius.all(Radius.circular( 10) // <--- border radius here )), child: Text('Synchronize ALL', style: TextStyle( color: SOFT_BLUE, fontWeight: FontWeight.bold)), ), ), ), ], ), ) ])); } Widget _buildVisitelistCard( VisiteModel visiteData, boxImageSize, animation, index) { return SizeTransition( sizeFactor: animation, child: GestureDetector( onTap: () { Route route = MaterialPageRoute( builder: (context) => VisitPhotoTypologyPage( pp_id_distrib: visiteData.id_distrib, pp_langage: visiteData.langage, pp_id_visite: visiteData.id_visite, pp_name: visiteData.name)); 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: visiteData.image, ), ), SizedBox( width: 10, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.only(top: 5), child: Row( children: [ Text(visiteData.name, style: GlobalStyle.productPrice) ], ), ), Container(height: 8), Text( visiteData.date, style: GlobalStyle.productSale, ), Container( margin: EdgeInsets.only(top: 5), child: Text( '${visiteData.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( ' ' + visiteData.type_visite, style: GlobalStyle.productName.copyWith( fontSize: 13, ), maxLines: 1, overflow: TextOverflow.ellipsis, ) ], ), ), ], ), ) ], ), Container( margin: EdgeInsets.only(top: 12), child: Row( children: [ Expanded( child: (visiteData.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: () { Route route = MaterialPageRoute( builder: (context) => UploadPhotosPage( id_visite: visiteData.id_visite, photoPaths: [ 'sim_1682957196322406.jpeg', ], ), ); Navigator.push(context, route); }, 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, )), ), ], ), ) ], ), ), ), ), ), ); } /// Initializes data when the page loads. Future loadData() async { try { // data initialisation with today visits modelData = await VisiteModel.getAllVisit(); } catch (e) { // set errorMessage for debug _errorMessage = 'Error loading visits : $e'; } } }