import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/asset_tracking/asset_tracking_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'asset_tracking_item_view.dart'; import 'map_tracking_page.dart'; class AssetTrackingPage extends StatefulWidget { AssetTrackingPage({Key? key}) : super(key: key); @override _AssetTrackingPageState createState() { return _AssetTrackingPageState(); } } class _AssetTrackingPageState extends State with SingleTickerProviderStateMixin { int selectedIndex = 1; late AnimationController _animationController; late AssetTrackingProvider assetTrackingProvider; @override void initState() { super.initState(); assetTrackingProvider = Provider.of(context, listen: false); _animationController = AnimationController( duration: const Duration(milliseconds: 1200), vsync: this, ); _animationController.forward(); WidgetsBinding.instance.addPostFrameCallback((_) { assetTrackingProvider.reset(); getAssetsFromPenguin(); }); } Future getAssetsFromPenguin({bool loadMore = false}) async { await assetTrackingProvider.getAssetsFromPenguin( loadMore: loadMore, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: const DefaultAppBar(title: "Live Asset Tracking"), body: Column( // crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: double.infinity, child: SegmentedButton( multiSelectionEnabled: false, emptySelectionAllowed: false, expandedInsets: const EdgeInsets.only(left: 16, top: 8, right: 16, bottom: 8), style: SegmentedButton.styleFrom( side: BorderSide(color: AppColor.borderColor(context)), textStyle: AppTextStyles.bodyText, backgroundColor: AppColor.background(context), foregroundColor: context.isDark ? AppColor.neutral30 : AppColor.black20, selectedForegroundColor: AppColor.addItemButtonColor(context), selectedBackgroundColor: AppColor.primary10, ), segments: >[ ButtonSegment( value: 1, label: const Text("List"), icon: Icon(Icons.list_rounded, color: AppColor.icon2Color(context)), ), ButtonSegment( value: 2, label: const Text("Grid"), icon: Icon(Icons.grid_view_rounded, color: AppColor.icon2Color(context)), ), ButtonSegment( value: 3, label: const Text("Map"), icon: Icon(Icons.map, color: AppColor.icon2Color(context)), ), ], selected: {selectedIndex}, onSelectionChanged: (Set newSelection) { setState(() { selectedIndex = newSelection.first; }); }, ), ), SafeArea( child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: selectedIndex == 1 ? assetsListView() : selectedIndex == 2 ? assetsGridView() : MapTrackingPage() // selectedIndex == 3 ? MapTrackingPage() : assetsListView(), ), ).expanded, ], ), ); } Widget assetsListView() { return Consumer(builder: (context, provider, _) { return (provider.assetsList.isEmpty && !provider.isLoading) ? NoDataFound(message: context.translation.noDataFound).center : NotificationListener( onNotification: (scrollInfo) { if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { getAssetsFromPenguin(loadMore: true); } return false; }, child: ListView.separated( key: const ValueKey('asset-list_view'), padding: const EdgeInsets.all(16), itemCount: provider.isLoading ? 6 : provider.assetsList.length + (provider.isNextPageLoading ? 1 : 0), separatorBuilder: (listContext, itemIndex) => 12.height, itemBuilder: (listContext, itemIndex) { if (provider.isLoading) return const SizedBox().toAssetListShimmer(listContext, provider.isLoading); if (itemIndex >= provider.assetsList.length) { return const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: ALoading(), ); } final delay = itemIndex * 0.08; final animation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: Interval( delay.clamp(0.0, 0.7), (delay + 0.4).clamp(0.0, 1.0), curve: Curves.easeOut, ), ), ); final slideAnimation = Tween( begin: const Offset(0.0, 0.15), end: Offset.zero, ).animate( CurvedAnimation( parent: _animationController, curve: Interval( delay.clamp(0.0, 0.7), (delay + 0.4).clamp(0.0, 1.0), curve: Curves.easeOutCubic, ), ), ); return FadeTransition( opacity: animation, child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex], false)).onPress(() { Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); }), ); }, ), ); }); } Widget assetsGridView() { return Consumer(builder: (context, provider, _) { return (provider.assetsList.isEmpty && !provider.isLoading) ? NoDataFound(message: context.translation.noDataFound).center : NotificationListener( onNotification: (scrollInfo) { if (!provider.isLoading && !provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels >= (scrollInfo.metrics.maxScrollExtent - 200)) { getAssetsFromPenguin(loadMore: true); } return false; }, child: Column( children: [ Expanded( child: GridView.builder( key: const ValueKey('asset-grid_view'), padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1.2, // need to fix this it's not flexiable with content.. crossAxisSpacing: 12, mainAxisSpacing: 12, ), itemCount: provider.isLoading ? 6 : provider.assetsList.length, // separatorBuilder: (listContext, itemIndex) => 12.height, itemBuilder: (listContext, itemIndex) { if (provider.isLoading) return const SizedBox().toAssetListShimmer(listContext, provider.isLoading); // Calculate staggered animation delay final delay = itemIndex * 0.08; final animation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: Interval( delay.clamp(0.0, 0.7), (delay + 0.4).clamp(0.0, 1.0), curve: Curves.easeOut, ), ), ); final slideAnimation = Tween( begin: const Offset(0.0, 0.15), end: Offset.zero, ).animate( CurvedAnimation( parent: _animationController, curve: Interval( delay.clamp(0.0, 0.7), (delay + 0.4).clamp(0.0, 1.0), curve: Curves.easeOutCubic, ), ), ); return FadeTransition( opacity: animation, child: SlideTransition(position: slideAnimation, child: AssetTrackingListItemView(provider.assetsList[itemIndex], true)).onPress(() { Navigator.push(context, MaterialPageRoute(builder: (context) => MapTrackingPage(assetTrackingData: provider.assetsList[itemIndex]))); }), ); }, ), ), if (provider.isNextPageLoading) const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: ALoading(), ), ], ), ); }); } }