diff --git a/lib/modules/copilot/controller/copilot_provider.dart b/lib/modules/copilot/controller/copilot_provider.dart index 4936c2cd..8387f3de 100644 --- a/lib/modules/copilot/controller/copilot_provider.dart +++ b/lib/modules/copilot/controller/copilot_provider.dart @@ -18,6 +18,7 @@ class CopilotProvider extends ChangeNotifier { String? sessionId; String? errorMessage; StreamSubscription? _streamSub; + Future loadHistory() async { historyLoading = true; errorMessage = null; @@ -41,19 +42,18 @@ class CopilotProvider extends ChangeNotifier { notifyListeners(); } } + Future deleteHistory(String threadId) async { final prevList = List.from(history); - history.removeWhere((h) => h.threadId == threadId); - notifyListeners(); try { - final res = await ApiManager.instance.delete( - URLs.copilotDeleteQueryHistory(threadId), - body: const {}, // API ignores the body for this route-bound id endpoint - ); + final res = await ApiManager.instance.delete(URLs.copilotDeleteQueryHistory(threadId), body: const {}); final decoded = jsonDecode(res.body); final success = decoded is Map && decoded['isSuccess'] == true && decoded['data'] == true; - if (!success) { + if (success) { + history.removeWhere((h) => h.threadId == threadId); + notifyListeners(); + } else { history = prevList; // rollback on failure errorMessage = (decoded is Map ? decoded['message'] : null) ?? "Failed to delete"; notifyListeners(); @@ -90,6 +90,7 @@ class CopilotProvider extends ChangeNotifier { notifyListeners(); } } + void startNewConversation() { _streamSub?.cancel(); sessionId = null; @@ -124,6 +125,7 @@ class CopilotProvider extends ChangeNotifier { _onStreamError(assistantMsg, e); } } + Future sendAudio(File audioFile) async { if (isStreaming) return; sessionId ??= _generateSessionId(); @@ -218,8 +220,7 @@ class CopilotProvider extends ChangeNotifier { return; } notifyListeners(); - } catch (_) { - } + } catch (_) {} } void _onStreamError(CopilotMessage assistantMsg, Object e) { @@ -247,11 +248,3 @@ class CopilotProvider extends ChangeNotifier { super.dispose(); } } - - - - - - - - diff --git a/lib/modules/copilot/model/copilot_message_model.dart b/lib/modules/copilot/model/copilot_message_model.dart index 5c046447..0162c6e6 100644 --- a/lib/modules/copilot/model/copilot_message_model.dart +++ b/lib/modules/copilot/model/copilot_message_model.dart @@ -44,6 +44,7 @@ class CopilotMessage { DateTime? timestamp; bool isStreaming; bool isError; + // Local path of a recorded audio file for a user's voice query (never a remote // download URL - the backend never sends audio back). Used to let the user // replay their own sent voice message, same as Chat's audio playback. @@ -120,7 +121,7 @@ class CopilotStreamContent { class CopilotHistoryItem { final String threadId; final String firstHumanMessage; - final DateTime updatedAt; + final String updatedAt; CopilotHistoryItem({ required this.threadId, @@ -131,7 +132,6 @@ class CopilotHistoryItem { factory CopilotHistoryItem.fromJson(Map json) => CopilotHistoryItem( threadId: json['threadId'] ?? '', firstHumanMessage: json['firstHumanMessage'] ?? '', - updatedAt: DateTime.tryParse(json['updatedAt'] ?? '') ?? DateTime.now(), + updatedAt: json['updatedAt'] ?? '', ); } - diff --git a/lib/modules/copilot/screens/copilot_chat_page.dart b/lib/modules/copilot/screens/copilot_chat_page.dart index 108edf63..a3af5b17 100644 --- a/lib/modules/copilot/screens/copilot_chat_page.dart +++ b/lib/modules/copilot/screens/copilot_chat_page.dart @@ -12,7 +12,9 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import '../controller/copilot_provider.dart'; import '../widgets/copilot_message_bubble.dart'; + enum _InputState { idle, recording, recorded } + class CopilotChatPage extends StatefulWidget { final bool isNewConversation; @@ -106,11 +108,17 @@ class _CopilotChatPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: DefaultAppBar(title: "Copilot Assistant", actions: [ - 'history_icon'.toSvgAsset(width: 24, height: 24).onPress((){ - Navigator.push(context, MaterialPageRoute(builder: (_) => const CopilotHistoryPage())).then((_) => context.read().loadHistory()); - }).paddingOnly(end: 12), - ],), + appBar: DefaultAppBar( + title: "Copilot Assistant", + actions: [ + IconButton( + onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const CopilotHistoryPage())), + style: const ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap), + icon: "history_icon".toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)), + constraints: const BoxConstraints(), + ), + ], + ), body: Column( children: [ Expanded( @@ -326,7 +334,7 @@ class _ShimmerBubble extends StatelessWidget { ).toShimmer(context: context, isShow: true); final name = Text( - isSender ? "Me" : "Copilot",//check the api if they send the user name + isSender ? "Me" : "Copilot", //check the api if they send the user name style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), ).toShimmer(context: context, isShow: true); @@ -360,8 +368,3 @@ class _ShimmerBubble extends StatelessWidget { ); } } - - - - - diff --git a/lib/modules/copilot/screens/copilot_history_page.dart b/lib/modules/copilot/screens/copilot_history_page.dart index 4b3b9364..990144f7 100644 --- a/lib/modules/copilot/screens/copilot_history_page.dart +++ b/lib/modules/copilot/screens/copilot_history_page.dart @@ -3,8 +3,10 @@ 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/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/modules/copilot/model/copilot_message_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; @@ -38,38 +40,37 @@ class _CopilotHistoryPageState extends State { } void _openConversation(String threadId) { - Navigator.push( - context, - CupertinoPageRoute( - builder: (_) => const CopilotChatPage( - isNewConversation: false, - ), - ), - ).then( - (_) => context.read().loadHistory(), - ); + // Navigator.push( + // context, + // CupertinoPageRoute( + // builder: (_) => const CopilotChatPage( + // isNewConversation: false, + // ), + // ), + // ).then( + // (_) => context.read().loadHistory(), + // ); context.read().loadConversation(threadId); + Navigator.pop(context); } void _startNewConversation() { context.read().startNewConversation(); - - Navigator.push( - context, - CupertinoPageRoute( - builder: (_) => const CopilotChatPage( - isNewConversation: true, - ), - ), - ).then( - (_) => context.read().loadHistory(), - ); + Navigator.pop(context); + // Navigator.push( + // context, + // CupertinoPageRoute( + // builder: (_) => const CopilotChatPage( + // isNewConversation: true, + // ), + // ), + // ).then( + // (_) => context.read().loadHistory(), + // ); } - List _filteredHistory( - List history, - ) { + List _filteredHistory(List history) { final query = _searchQuery.trim().toLowerCase(); if (query.isEmpty) { @@ -88,8 +89,10 @@ class _CopilotHistoryPageState extends State { title: "Copilot History", actions: [ IconButton( - icon: const Icon(Icons.chat_bubble), onPressed: _startNewConversation, + style: const ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap), + icon: Icon(Icons.chat_bubble, color: AppColor.icon2Color(context)), + constraints: const BoxConstraints(), ), ], ), @@ -106,12 +109,6 @@ class _CopilotHistoryPageState extends State { mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon( - Icons.chat_bubble_outline, - size: 56, - color: AppColor.neutral120, - ), - 16.height, Text( "No conversations yet", style: AppTextStyles.heading6.copyWith( @@ -135,27 +132,20 @@ class _CopilotHistoryPageState extends State { final filteredHistory = _filteredHistory(provider.history); return Column( + spacing: 8, children: [ - 8.height, _buildSearchBar(context), - 8.height, if (filteredHistory.isEmpty) Expanded( child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon( - Icons.search_off, - size: 48, - color: AppColor.neutral120, - ), + Icon(Icons.search_off, color: AppColor.icon2Color(context), size: 20), 12.height, Text( "No conversations found", - style: AppTextStyles.heading6.copyWith( - color: AppColor.neutral120, - ), + style: AppTextStyles.heading6.copyWith(color: AppColor.lightTextColor(context)), ), ], ).center, @@ -163,18 +153,13 @@ class _CopilotHistoryPageState extends State { else Expanded( child: ListView.separated( - padding: const EdgeInsets.symmetric( - horizontal: 16, - ), + padding: const EdgeInsets.all(16), itemCount: filteredHistory.length, separatorBuilder: (context, index) => 12.height, itemBuilder: (context, index) { final item = filteredHistory[index]; - return messageHistoryCard( - item: item, - provider: provider, - ); + return messageHistoryCard(item: item, provider: provider); }, ), ), @@ -186,91 +171,56 @@ class _CopilotHistoryPageState extends State { } Widget _buildSearchBar(BuildContext context) { - return AppTextFormField( - labelText: "", - hintText: context.translation.search, - showBorder: false, - showShadow: false, - // backgroundColor: AppColor.fieldBgColor(context), - prefixIcon: Icon( - Icons.search, - color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, - size: 19, + return SearchBar( + // focusNode: searchFocusNode, + elevation: WidgetStateProperty.all(0), + backgroundColor: WidgetStateProperty.all(AppColor.background(context)), + leading: Icon(Icons.search, color: AppColor.iconColor(context)), + textStyle: WidgetStateProperty.all( + TextStyle(color: AppColor.textColor(context), fontSize: 16.0), ), - textInputType: TextInputType.text, - contentPadding: EdgeInsets.zero, - hintStyle: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, + hintStyle: WidgetStateProperty.all( + TextStyle(color: AppColor.textColor(context), fontSize: 14.0), ), - style: AppTextStyles.bodyText.copyWith( - color: AppColor.textStyleColor(context), - ), - onChange: (value) { - setState(() { - _searchQuery = value; - }); + hintText: 'Search', + onChanged: (queryString) { + _searchQuery = queryString; + setState(() {}); }, - ) - .toShadowContainer( - context, - showShadow: false, - ) - .paddingOnly(start: 16, end: 16); + ).paddingOnly(top: 16, start: 16, end: 16); } - Widget messageHistoryCard({ - required CopilotHistoryItem item, - required CopilotProvider provider, - }) { + Widget messageHistoryCard({required CopilotHistoryItem item, required CopilotProvider provider}) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 12, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + Icon( + Icons.chat_bubble, + color: AppColor.icon2Color(context), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + spacing: 4, children: [ - Icon( - Icons.chat_bubble, - color: AppColor.icon2Color(context), - ), - 16.width, - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - InfoHeaderWidget( - item.firstHumanMessage, - ), - 4.height, - InfoTextLabelWidget( - label: _formatDate(item.updatedAt), - ), - ], - ), + InfoHeaderWidget(item.firstHumanMessage), + InfoTextLabelWidget(label: item.updatedAt.toServiceRequestDetailsFormat), ], + ).expanded, + IconButton( + onPressed: () async { + Utils.showLoading(context); + await provider.deleteHistory(item.threadId); + Utils.hideLoading(context); + }, + style: const ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap), + icon: "delete_icon".toSvgAsset(width: 20, height: 20), + constraints: const BoxConstraints(), ), - "delete_icon" - .toSvgAsset( - height: 20, - width: 20, - ) - .onPress( - () => provider.deleteHistory(item.threadId), - ), ], - ) - .toShadowContainer( - context, - showShadow: false, - ) - .onPress(() { + ).toShadowContainer(context).onPress(() { _openConversation(item.threadId); }); } - - String _formatDate(DateTime date) { - return "${date.day.toString().padLeft(2, '0')}/" - "${date.month.toString().padLeft(2, '0')}/" - "${date.year} " - "${date.hour.toString().padLeft(2, '0')}:" - "${date.minute.toString().padLeft(2, '0')}"; - } } diff --git a/lib/modules/copilot/widgets/copilot_message_bubble.dart b/lib/modules/copilot/widgets/copilot_message_bubble.dart index 6ebd46c0..e62ea1a1 100644 --- a/lib/modules/copilot/widgets/copilot_message_bubble.dart +++ b/lib/modules/copilot/widgets/copilot_message_bubble.dart @@ -5,6 +5,7 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart'; import 'package:url_launcher/url_launcher.dart'; import '../model/copilot_message_model.dart'; @@ -33,12 +34,7 @@ class CopilotMessageBubble extends StatelessWidget { final senderHeader = Row( mainAxisSize: MainAxisSize.min, children: [ - Text( - "Me", - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), - ), + const InfoTextLabelWidget(label: "Me"), 8.width, _avatar, ], @@ -61,7 +57,8 @@ class CopilotMessageBubble extends StatelessWidget { padding: const EdgeInsets.all(8), constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.75), decoration: BoxDecoration( - color: AppColor.white50, + color: AppColor.assetGroupBackground(context), + border: Border.all(color: AppColor.borderColor(context)), borderRadius: BorderRadius.circular(6), ), child: Column( @@ -98,12 +95,13 @@ class CopilotMessageBubble extends StatelessWidget { children: [ _avatar, 8.width, - Text( - "Copilot", - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), - ), + const InfoTextLabelWidget(label: "Copilot"), + // Text( + // "Copilot", + // overflow: TextOverflow.ellipsis, + // maxLines: 1, + // style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), + // ), ], ); return Align( @@ -119,6 +117,7 @@ class CopilotMessageBubble extends StatelessWidget { constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.75), decoration: BoxDecoration( color: AppColor.background(context), + border: Border.all(color: AppColor.borderColor(context)), borderRadius: BorderRadius.circular(6), ), child: Column( diff --git a/lib/new_views/common_widgets/app_drawer.dart b/lib/new_views/common_widgets/app_drawer.dart index f9758ff3..3ef90ef7 100644 --- a/lib/new_views/common_widgets/app_drawer.dart +++ b/lib/new_views/common_widgets/app_drawer.dart @@ -30,18 +30,15 @@ class AppDrawer extends StatelessWidget { final settingProvider = Provider.of(context, listen: false); final userProvider = Provider.of(context, listen: false); return Drawer( - backgroundColor: AppColor.background(context), - width: MediaQuery - .of(context) - .size - .width * .8, - child: SafeArea( - top: false, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( + backgroundColor: AppColor.background(context), + width: MediaQuery.of(context).size.width * .8, + child: SafeArea( + top: false, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -55,8 +52,8 @@ class AppDrawer extends StatelessWidget { child: snapshot.profileImage != null ? Image.file(snapshot.profileImage!) : (snapshot.user?.profilePhotoName?.isNotEmpty ?? false) - ? Image.network(snapshot.user!.profilePhotoName!) - : Icon(Icons.person, size: 50, color: AppColor.icon2Color(context)), + ? Image.network(snapshot.user!.profilePhotoName!) + : Icon(Icons.person, size: 50, color: AppColor.icon2Color(context)), ), ), ); @@ -66,72 +63,72 @@ class AppDrawer extends StatelessWidget { ), 8.height, (userProvider.user?.username ?? "").heading4(context).custom(color: AppColor.labelTextStyleColor(context)), - if ((userProvider.user?.email ?? "").isNotEmpty)(userProvider.user!.email!).heading6(context).custom(color: AppColor.lightTextColor(context)), - 16.height, - const Divider().defaultStyle(context), - ListView( - padding: const EdgeInsets.only(top: 24), - children: [ - // drawerItem("drawer_notification", context.translation.notifications, context).onPress(() => Navigator.of(context).pushNamed(NotificationsPage.id)), - // 18.height, - // drawerItem("notification_setting", 'Notification Settings'.addTranslation, context).onPress(() => Navigator.of(context).pushNamed(NotificationSettingPage.id)), - // 18.height, - // drawerItem("help_center", context.translation.helpCenter, context) /*.onPress(() => Navigator.of(context).pushNamed(HelpCenterPage.id))*/, - // 18.height, - // drawerItem("rate_us", context.translation.rateUs, context), - // 18.height, - drawerItem("setting", context.translation.settings, context).onPress(() => Navigator.of(context).pushNamed(SettingsPage.id)), - 18.height, - drawerItem("setting", "Copilot", context).onPress(() { - context.read().startNewConversation(); - Navigator.push(context, MaterialPageRoute(builder: (_) => const CopilotChatPage(isNewConversation: true))).then((_) => context.read().loadHistory()); - }), + if ((userProvider.user?.email ?? "").isNotEmpty) (userProvider.user!.email!).heading6(context).custom(color: AppColor.lightTextColor(context)), + 16.height, + const Divider().defaultStyle(context), + ListView( + padding: const EdgeInsets.only(top: 24), + children: [ + // drawerItem("drawer_notification", context.translation.notifications, context).onPress(() => Navigator.of(context).pushNamed(NotificationsPage.id)), + // 18.height, + // drawerItem("notification_setting", 'Notification Settings'.addTranslation, context).onPress(() => Navigator.of(context).pushNamed(NotificationSettingPage.id)), + // 18.height, + // drawerItem("help_center", context.translation.helpCenter, context) /*.onPress(() => Navigator.of(context).pushNamed(HelpCenterPage.id))*/, + // 18.height, + // drawerItem("rate_us", context.translation.rateUs, context), + // 18.height, + drawerItem("setting", context.translation.settings, context).onPress(() => Navigator.of(context).pushNamed(SettingsPage.id)), + 18.height, + drawerItem("setting", "Copilot", context).onPress(() { + context.read().startNewConversation(); + Navigator.push(context, MaterialPageRoute(builder: (_) => const CopilotChatPage(isNewConversation: true))).then((_) => context.read().loadHistory()); + }), - 18.height, - drawerItem("site_request_icon", "Site Request", context).onPress(() => Navigator.of(context).pushNamed(SiteRequestHistoryScreen.routeName)), - 18.height, - if (userProvider.user != null && settingProvider.isUserFlowMedical == false && userProvider.user?.employeeIsHMG == false) - drawerItem("swipe", "Swipe History", context).onPress(() => Navigator.of(context).pushNamed(SwipeHistoryView.routeName)), - // 18.height, - // drawerItem("report", context.translation.reportBg, context) /*.onPress(() => Navigator.of(context).pushNamed(ReportBugPage.id))*/, - // 18.height, - // drawerItem("whats_new", context.translation.whatsNew, context), - ], - ).expanded, - drawerItem("logout", context.translation.logout, context, color: AppColor.red30).onPress(() async { - bool result = await showDialog( - context: context, - builder: (_) => AAlertDialog(title: context.translation.signOut, content: context.translation.logoutAlert), - ); - if (result) { - bool isSuccess = await userProvider.logout(context); - if (isSuccess) { - settingProvider.resetSettings(); - userProvider.reset(); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); - } - } - }), - 16.height, - const Divider().defaultStyle(context), - 16.height, - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Powered By Cloud Solutions", - style: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontSize: 12), - textScaleFactor: AppStyle.getScaleFactor(context), - ), - 6.width, - Image.asset("assets/images/cloud_logo.png", width: 32, height: 32) - ], - ) - ], - ).paddingOnly(top: 66, start: 16, end: 24, bottom: 18), - ), + 18.height, + drawerItem("site_request_icon", "Site Request", context).onPress(() => Navigator.of(context).pushNamed(SiteRequestHistoryScreen.routeName)), + 18.height, + if (userProvider.user != null && settingProvider.isUserFlowMedical == false && userProvider.user?.employeeIsHMG == false) + drawerItem("swipe", "Swipe History", context).onPress(() => Navigator.of(context).pushNamed(SwipeHistoryView.routeName)), + // 18.height, + // drawerItem("report", context.translation.reportBg, context) /*.onPress(() => Navigator.of(context).pushNamed(ReportBugPage.id))*/, + // 18.height, + // drawerItem("whats_new", context.translation.whatsNew, context), + ], + ).expanded, + drawerItem("logout", context.translation.logout, context, color: AppColor.red30).onPress(() async { + bool result = await showDialog( + context: context, + builder: (_) => AAlertDialog(title: context.translation.signOut, content: context.translation.logoutAlert), + ); + if (result) { + bool isSuccess = await userProvider.logout(context); + if (isSuccess) { + settingProvider.resetSettings(); + userProvider.reset(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + } + } + }), + 16.height, + const Divider().defaultStyle(context), + 16.height, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Powered By Cloud Solutions", + style: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontSize: 12), + textScaleFactor: AppStyle.getScaleFactor(context), + ), + 6.width, + Image.asset("assets/images/cloud_logo.png", width: 32, height: 32) + ], + ) + ], + ).paddingOnly(top: 66, start: 16, end: 24, bottom: 18), + ), ); } diff --git a/lib/views/widgets/equipment/my_assets_page.dart b/lib/views/widgets/equipment/my_assets_page.dart index 974fd563..db37941c 100644 --- a/lib/views/widgets/equipment/my_assets_page.dart +++ b/lib/views/widgets/equipment/my_assets_page.dart @@ -697,8 +697,8 @@ class _MyAssetsPageState extends State with SingleTickerProviderSt if (predictedAssetList.isNotEmpty) { Navigator.push(context, MaterialPageRoute(builder: (context) => PredictDeviceView(predictedAsset: predictedAssetList))); } else { - Fluttertoast.showToast(msg: 'No Predicted asset found', toastLength: Toast.LENGTH_LONG); - debugPrint('No Predicted asset found in the response.'); + context.showInfoDialog("No Predicted asset found"); + // Fluttertoast.showToast(msg: 'No Predicted asset found', toastLength: Toast.LENGTH_LONG); } } } catch (e) { diff --git a/lib/views/widgets/equipment/predict_device_list.dart b/lib/views/widgets/equipment/predict_device_list.dart index cf1dc48b..7d2fdc6a 100644 --- a/lib/views/widgets/equipment/predict_device_list.dart +++ b/lib/views/widgets/equipment/predict_device_list.dart @@ -23,8 +23,6 @@ class PredictDeviceView extends StatefulWidget { } class _PredictDeviceViewState extends State with SingleTickerProviderStateMixin { - late AssetProvider _devicesProvider; - bool showListView = true; late AnimationController _animationController; @override @@ -45,133 +43,56 @@ class _PredictDeviceViewState extends State with SingleTicker @override Widget build(BuildContext context) { - _devicesProvider = Provider.of(context); return Scaffold( - resizeToAvoidBottomInset: false, - appBar: DefaultAppBar( - title: 'Predicated Devices', - actions: [ - IconButton( - icon: Icon(!showListView ? Icons.view_list_sharp : Icons.grid_view_outlined, color: AppColor.icon2Color(context)), - padding: EdgeInsets.zero, - iconSize: 20, - visualDensity: VisualDensity.compact, - tooltip: !showListView ? "View as List" : "View as Grid", - onPressed: () => setState(() { - showListView = !showListView; - }), - ), - ], - ), - body: Stack( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 500), - child: showListView - ? ListView.separated( - key: const ValueKey('list_view'), - padding: const EdgeInsets.all(16), - itemCount: widget.predictedAsset.length, - separatorBuilder: (listContext, itemIndex) => 12.height, - itemBuilder: (listContext, itemIndex) { - // 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: PredictDeviceItemView( - device: widget.predictedAsset[itemIndex], - onPressed: (device) { - int? assetId = int.tryParse(device.assetId??''); - Navigator.of(context).pushNamed(AssetDetailPage.id, arguments:assetId ); - }, - ), - ), - ); - }, - ) - : GridView.builder( - key: const ValueKey('grid_view'), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 12, - childAspectRatio: 1.5, - mainAxisSpacing: 12), - itemCount: widget.predictedAsset.length, - padding: const EdgeInsets.all(16), - itemBuilder: (context, index) { - // Calculate staggered animation delay - final delay = index * 0.08; - final animation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.8), - (delay + 0.3).clamp(0.0, 1.0), - curve: Curves.easeOut, - ), - ), - ); + appBar: const DefaultAppBar(title: 'Predicated Devices'), + body: SafeArea( + child: ListView.separated( + key: const ValueKey('list_view'), + padding: const EdgeInsets.all(16), + itemCount: widget.predictedAsset.length, + separatorBuilder: (listContext, itemIndex) => 12.height, + itemBuilder: (listContext, itemIndex) { + // 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.3), - end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - delay.clamp(0.0, 0.8), - (delay + 0.3).clamp(0.0, 1.0), - curve: Curves.easeOutCubic, - ), - ), - ); + 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: PredictDeviceItemGridView( - device: widget.predictedAsset[index], - onPressed: (device) { - //We are not getting asset id in response only have serial number - int? assetId = int.tryParse(device.assetId??''); - Navigator.of(context).pushNamed(AssetDetailPage.id, arguments:assetId ); - }, - ), - ), - ); - }, - ), + return FadeTransition( + opacity: animation, + child: SlideTransition( + position: slideAnimation, + child: PredictDeviceItemView( + device: widget.predictedAsset[itemIndex], + onPressed: (device) { + int? assetId = int.tryParse(device.assetId ?? ''); + Navigator.of(context).pushNamed(AssetDetailPage.id, arguments: assetId); + }, ), - ], - ), - ); + ), + ); + }, + ))); } }