/* This is home page we used AutomaticKeepAliveClientMixin to keep the state when moving from 1 navbar to another navbar, so the page is not refresh overtime */ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/cubit/language/language_cubit.dart'; 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/model/visite_model.dart'; import 'package:mobdr/ui/general/chat_us.dart'; import 'package:mobdr/ui/general/notification.dart'; import 'package:mobdr/ui/home/visit_photo_typology.dart'; import 'package:mobdr/ui/reusable/reusable_widget.dart'; import 'package:mobdr/ui/reusable/cache_image_network.dart'; class TabHomePage extends StatefulWidget { @override _TabHomePageState createState() => _TabHomePageState(); } class _TabHomePageState extends State with AutomaticKeepAliveClientMixin { // initialize global function and reusable widget final _reusableWidget = ReusableWidget(); // _listKey is used for AnimatedList final GlobalKey _listKey = GlobalKey(); // keep the state to do not refresh when switch navbar @override bool get wantKeepAlive => true; String defaultLang = 'en'; late LanguageCubit _languageCubit; bool _isLoading = true; String _errorMessage = ''; late List modelData = []; @override void initState() { super.initState(); _languageCubit = BlocProvider.of(context); _getLocale().then((val) { setState(() { defaultLang = val!; }); }); loadData().then((_) { setState(() { _isLoading = false; }); }); } @override void dispose() { super.dispose(); } Future _getLocale() async { final SharedPreferences _pref = await SharedPreferences.getInstance(); String? lCode = _pref.getString('lCode'); return lCode; } void changeLocale(Locale locale) async { final SharedPreferences _pref = await SharedPreferences.getInstance(); await _pref.setString('lCode', locale.languageCode); await _pref.setString('cCode', locale.countryCode!); _languageCubit.changeLanguage(locale); defaultLang = locale.languageCode; } @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('Aucune visite trouvée.'), ); } return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, elevation: GlobalStyle.appBarElevation, title: Text( AppLocalizations.of(context)!.translate('i18n_hello')! + ', ${SharedPrefs().prenom}', style: GlobalStyle.appBarTitle, ), backgroundColor: GlobalStyle.appBarBackgroundColor, systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle, actions: [ GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => ChatUsPage())); }, child: Icon(Icons.email, color: BLACK_GREY)), IconButton( icon: _reusableWidget.customNotifIcon( count: 8, notifColor: BLACK_GREY), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => NotificationPage())); }), ], ), body: AnimatedList( key: _listKey, initialItemCount: modelData.length, physics: AlwaysScrollableScrollPhysics(), itemBuilder: (context, index, animation) { return _buildVisitelistCard( modelData[index], boxImageSize, animation, index); }, )); } Widget _buildVisitelistCard( VisiteModel visiteData, boxImageSize, animation, index) { return SizeTransition( sizeFactor: animation, child: Container( margin: EdgeInsets.fromLTRB(12, 6, 12, 0), 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, onRefreshVisit: (int photoCount) { setState(() { modelData[index].photoCount = photoCount; }); }, )); Navigator.push(context, route); }, 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(height: 8), Text( visiteData.name, style: GlobalStyle.productName.copyWith( fontSize: 13, ), maxLines: 3, overflow: TextOverflow.ellipsis, ), Container( margin: EdgeInsets.only(top: 5), child: Text( visiteData.date, style: GlobalStyle.productSale, ), ), Container(height: 5), Container( margin: EdgeInsets.only(top: 5), child: Text( '${visiteData.photoCount} Photo(s)', style: GlobalStyle.productPrice, ), ), Container(height: 5), 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, ) ], ), ), ], ), ) ], ), ], ), ), ), ), ), ); } /// Called when a visit is refreshed with new photo count. /// /// [index]: The index of the visit being refreshed. /// [newPhotoCount]: The new photo count for the visit. void onRefreshVisit(int index, int newPhotoCount) { setState(() { modelData[index].photoCount = newPhotoCount; }); } /// Initializes data when the page loads. Future loadData() async { try { // visite model initialisation modelData = await VisiteModel.getAllVisites(); } catch (e) { // set errorMessage for debug _errorMessage = 'Error loading visites : $e'; } } }