From 8cd3e8aa3bbab046d826c1b362514ef6be3d3d9a Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Mon, 11 May 2026 09:49:07 +0300 Subject: [PATCH] export improvements --- lib/modules/cm_module/cm_detail_page.dart | 131 ++--------------- .../export_module/pages/export_form_view.dart | 106 ++------------ .../provider/export_provider.dart | 32 +++-- .../widgets/file_success_dialog.dart | 134 ++++++++++++++++++ 4 files changed, 181 insertions(+), 222 deletions(-) create mode 100644 lib/modules/export_module/widgets/file_success_dialog.dart diff --git a/lib/modules/cm_module/cm_detail_page.dart b/lib/modules/cm_module/cm_detail_page.dart index dfd6707a..35fc8d45 100644 --- a/lib/modules/cm_module/cm_detail_page.dart +++ b/lib/modules/cm_module/cm_detail_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -17,15 +16,12 @@ import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; import 'package:test_sa/modules/cx_module/chat/chat_widget.dart'; import 'package:test_sa/modules/export_module/provider/export_provider.dart'; +import 'package:test_sa/modules/export_module/widgets/file_success_dialog.dart'; import 'package:test_sa/modules/loan_module/pages/create_loan_request_page.dart'; import 'package:test_sa/modules/loan_module/pages/loan_equipment_detail_page.dart'; import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; -import 'package:open_file/open_file.dart'; -import 'package:share_plus/share_plus.dart'; -import 'dart:developer'; import 'views/components/history_log_view.dart'; import 'views/components/service_request_detail_view.dart'; @@ -176,7 +172,8 @@ class _CMDetailPageState extends State { }), // Print Button IconButton( - icon: const Icon(Icons.print), + icon: "download".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)), + padding: EdgeInsets.zero, onPressed: _handlePrint, ), IconButton( @@ -255,105 +252,6 @@ class _CMDetailPageState extends State { cProvider.getUserAutoLoginTokenSilent(moduleId, widget.requestId, title, myEmployeeId, receiver); } - /// Show success dialog after file is downloaded - using same implementation as export module - Future _showSuccessDialog(String filePath) async { - if (!mounted) return; - - return showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext dialogContext) { - return Dialog( - backgroundColor: AppColor.background(context), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SvgPicture.asset( - 'assets/images/done.svg', - width: 80, - height: 80, - ), - const SizedBox(height: 24), - Text( - 'Print Successful', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColor.headingTextColor(context), - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 12), - Text( - 'Your PDF has been generated successfully', - style: TextStyle( - fontSize: 14, - color: AppColor.lightTextColor(context), - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 32), - Row( - children: [ - Expanded( - child: AppFilledButton( - onPressed: () async { - Navigator.of(dialogContext).pop(); - log('📂 Opening printed file...'); - final result = await OpenFile.open(filePath); - if (result.type != ResultType.done) { - log('⚠️ Could not open file: ${result.message}'); - 'No app found to open this file type. File saved to: $filePath'.showToast; - } - }, - label: 'Open', - buttonColor: AppColor.primary10, - showIcon: true, - icon: const Icon(Icons.folder_open, color: Colors.white), - height: 48, - ), - ), - const SizedBox(width: 12), - Expanded( - child: AppFilledButton( - onPressed: () async { - Navigator.of(dialogContext).pop(); - log('📤 Sharing printed file...'); - try { - final xFile = XFile(filePath); - await Share.shareXFiles( - [xFile], - text: 'Printed file', - ); - log('✅ File shared successfully'); - } catch (e) { - log('❌ Error sharing file: $e'); - 'Failed to share file: $e'.showToast; - } - }, - label: 'Share', - buttonColor: AppColor.green40, - textColor: AppColor.green60, - showIcon: true, - icon: Icon(Icons.share, color: AppColor.green60), - height: 48, - ), - ), - ], - ), - ], - ), - ), - ); - }, - ); - } - /// Handle print button press Future _handlePrint() async { try { @@ -366,25 +264,22 @@ class _CMDetailPageState extends State { ); if (filePath != null) { - await _showSuccessDialog(filePath); + // Show success dialog using the reusable FileSuccessDialog widget + await FileSuccessDialog.show( + context: context, + filePath: filePath, + title: 'Print Successful', + message: 'Your PDF has been generated successfully', + logPrefix: 'printed', + ); } else if (exportProvider.errorMessage != null) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(exportProvider.errorMessage!), - backgroundColor: AppColor.red60, - ), - ); + exportProvider.errorMessage?.showToast; } } } catch (error) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Print failed: $error'), - backgroundColor: AppColor.red60, - ), - ); + 'Print Failed'.showToast; } } } diff --git a/lib/modules/export_module/pages/export_form_view.dart b/lib/modules/export_module/pages/export_form_view.dart index 237ac2e2..49744bb5 100644 --- a/lib/modules/export_module/pages/export_form_view.dart +++ b/lib/modules/export_module/pages/export_form_view.dart @@ -15,6 +15,7 @@ import 'package:test_sa/modules/export_module/models/export_module_type.dart'; import 'package:test_sa/modules/export_module/provider/export_provider.dart'; import 'package:test_sa/modules/export_module/provider/export_columns_provider.dart'; import 'package:test_sa/modules/export_module/provider/export_format_provider.dart'; +import 'package:test_sa/modules/export_module/widgets/file_success_dialog.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; @@ -22,6 +23,8 @@ import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.da import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'dart:developer'; +import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; + class ExportFormView extends StatefulWidget { final T searchModel; final ExportModuleType moduleType; @@ -133,7 +136,13 @@ class _ExportFormViewState extends State> { if (!mounted) return; if (filePath != null && filePath.isNotEmpty) { - await _showExportSuccessDialog(context, filePath); + await FileSuccessDialog.show( + context: context, + filePath: filePath, + title: 'Export Successful', + message: 'Your file has been exported successfully', + logPrefix: 'exported', + ); } else if (exportProvider.errorMessage != null) { String errorMessage = exportProvider.errorMessage!; if (errorMessage.contains('No app installed') || errorMessage.contains('No app found')) { @@ -158,101 +167,6 @@ class _ExportFormViewState extends State> { ); } - Future _showExportSuccessDialog(BuildContext context, String filePath) async { - return showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext dialogContext) { - return Dialog( - backgroundColor: AppColor.background(context), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SvgPicture.asset( - 'assets/images/done.svg', - width: 80, - height: 80, - ), - const SizedBox(height: 24), - Text( - 'Export Successful', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColor.headingTextColor(context), - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 12), - Text( - 'Your file has been exported successfully', - style: TextStyle( - fontSize: 14, - color: AppColor.lightTextColor(context), - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 32), - Row( - children: [ - Expanded( - child: AppFilledButton( - onPressed: () async { - Navigator.of(dialogContext).pop(); - log('📂 Opening exported file...'); - final result = await OpenFile.open(filePath); - if (result.type != ResultType.done) { - log('⚠️ Could not open file: ${result.message}'); - 'No app found to open this file type. File saved to: $filePath'.showToast; - } - }, - label: 'Open', - buttonColor: AppColor.primary10, - showIcon: true, - icon: const Icon(Icons.folder_open, color: Colors.white), - height: 48, - ), - ), - const SizedBox(width: 12), - Expanded( - child: AppFilledButton( - onPressed: () async { - Navigator.of(dialogContext).pop(); - log('📤 Sharing exported file...'); - try { - final xFile = XFile(filePath); - await Share.shareXFiles( - [xFile], - text: 'Exported file', - ); - log('✅ File shared successfully'); - } catch (e) { - log('❌ Error sharing file: $e'); - 'Failed to share file: $e'.showToast; - } - }, - label: 'Share', - buttonColor: AppColor.green40, - textColor: AppColor.green60, - showIcon: true, - icon: Icon(Icons.share, color: AppColor.green60), - height: 48, - ), - ), - ], - ), - ], - ), - ), - ); - }, - ); - } //check if we need we can show this as well @waseem diff --git a/lib/modules/export_module/provider/export_provider.dart b/lib/modules/export_module/provider/export_provider.dart index b6f5a486..dc496399 100644 --- a/lib/modules/export_module/provider/export_provider.dart +++ b/lib/modules/export_module/provider/export_provider.dart @@ -10,6 +10,7 @@ import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/modules/export_module/models/export_form_model.dart'; import 'package:test_sa/modules/export_module/models/export_module_type.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/extensions/context_extension.dart'; class ExportApiProvider extends ChangeNotifier { bool _isExporting = false; @@ -28,6 +29,12 @@ class ExportApiProvider extends ChangeNotifier { _isExporting = true; _errorMessage = null; notifyListeners(); + + // Capture colors before showing dialog to avoid Provider context issues + // Use isDarkNotListen to safely access provider without listening + final backgroundColor = context.isDarkNotListen ? AppColor.containerDark : Colors.white; + final textColor = context.isDarkNotListen ? AppColor.white10 : AppColor.white936; + ProgressDialog pd = ProgressDialog(context: context); pd.show( max: 100, @@ -35,10 +42,10 @@ class ExportApiProvider extends ChangeNotifier { progressBgColor: Colors.transparent, progressValueColor: AppColor.primary10, msgFontWeight: FontWeight.normal, - - // backgroundColor: AppColor.background(context), - // msgColor: AppColor.headingTextColor(context), - valueColor: AppColor.primary10, + msgColor: textColor, + valueColor: textColor, + msgFontSize: 18, + backgroundColor: backgroundColor, ); IOSink? sink; @@ -48,7 +55,7 @@ class ExportApiProvider extends ChangeNotifier { final String apiUrl = _getApiUrlForModule(moduleType); final Map body = _buildRequestBody(exportRequest, moduleType); if (!context.mounted) return null; - pd.update(msg: 'Sending request to server...'); + pd.update(msg: 'Sending request to server'); log('📡 Sending export request...'); final startTime = DateTime.now(); @@ -247,14 +254,23 @@ class ExportApiProvider extends ChangeNotifier { _errorMessage = null; notifyListeners(); + // Capture colors before showing dialog to avoid Provider context issues + // Use isDarkNotListen to safely access provider without listening + final backgroundColor = context.isDarkNotListen ? AppColor.containerDark : Colors.white; + final textColor = context.isDarkNotListen ? AppColor.white10 : AppColor.white936; + ProgressDialog pd = ProgressDialog(context: context); pd.show( max: 100, - msg: 'Preparing print...', + msg: 'Preparing print', progressBgColor: Colors.transparent, progressValueColor: AppColor.primary10, msgFontWeight: FontWeight.normal, - valueColor: AppColor.primary10, + msgFontSize: 18, + valueColor: textColor, + backgroundColor: backgroundColor, + msgColor: textColor, + ); IOSink? sink; @@ -262,7 +278,7 @@ class ExportApiProvider extends ChangeNotifier { try { if (!context.mounted) return null; - pd.update(msg: 'Sending print request...'); + pd.update(msg: 'Sending print request'); log('📡 Sending print request...'); final startTime = DateTime.now(); diff --git a/lib/modules/export_module/widgets/file_success_dialog.dart b/lib/modules/export_module/widgets/file_success_dialog.dart new file mode 100644 index 00000000..94b07e2f --- /dev/null +++ b/lib/modules/export_module/widgets/file_success_dialog.dart @@ -0,0 +1,134 @@ +import 'dart:developer'; +import 'package:flutter/material.dart'; +import 'package:open_file/open_file.dart'; +import 'package:share_plus/share_plus.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/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; + +/// Reusable success dialog for file operations (export, print, etc.) +class FileSuccessDialog { + /// Shows a success dialog with Open and Share options + /// + /// [context] - The build context + /// [filePath] - Path to the successfully generated file + /// [title] - Dialog title (e.g., 'Export Successful', 'Print Successful') + /// [message] - Dialog message (e.g., 'Your file has been exported successfully') + /// [logPrefix] - Prefix for log messages (e.g., 'exported', 'printed') + static Future show({ + required BuildContext context, + required String filePath, + required String title, + required String message, + String logPrefix = 'file', + }) async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) { + return Dialog( + backgroundColor: AppColor.background(context), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Close button + Align( + alignment: Alignment.topRight, + child: 'clear'.toSvgAsset( + color: AppColor.iconColor(context), + width: 18, + height: 18, + ).onPress(() { + Navigator.of(dialogContext).pop(); + }), + ), + // Success icon + 'done'.toSvgAsset(color: AppColor.green70, width: 56, height: 56), + const SizedBox(height: 24), + // Title + Text( + title, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: AppColor.headingTextColor(context), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + // Message + Text( + message, + style: TextStyle( + fontSize: 18, + color: AppColor.lightTextColor(context), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 32), + // Action buttons + Row( + children: [ + // Open button + Expanded( + child: AppFilledButton( + onPressed: () async { + log('📂 Opening $logPrefix file...'); + final result = await OpenFile.open(filePath); + if (result.type != ResultType.done) { + log('⚠️ Could not open file: ${result.message}'); + 'No app found to open this file type. File saved to: $filePath' + .showToast; + } + }, + label: 'Open', + buttonColor: AppColor.primary10, + showIcon: true, + icon: const Icon(Icons.folder_open, color: Colors.white), + height: 48, + ), + ), + const SizedBox(width: 12), + // Share button + Expanded( + child: AppFilledButton( + onPressed: () async { + log('📤 Sharing $logPrefix file...'); + try { + final xFile = XFile(filePath); + await Share.shareXFiles( + [xFile], + text: '${title.replaceAll(' Successful', '')} file', + ); + log('✅ File shared successfully'); + } catch (e) { + log('❌ Error sharing file: $e'); + 'Failed to share file: $e'.showToast; + } + }, + label: 'Share', + buttonColor: AppColor.green40, + textColor: AppColor.green60, + showIcon: true, + icon: const Icon(Icons.share, color: AppColor.green60), + height: 48, + ), + ), + ], + ), + ], + ), + ), + ); + }, + ); + } +} +