From 729a03e1a92a3da5100a6b0d80f53f3400a4f361 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Tue, 5 May 2026 14:26:23 +0300 Subject: [PATCH 1/5] Print request added for CM request --- lib/controllers/api_routes/api_manager.dart | 34 ++++ lib/controllers/api_routes/urls.dart | 4 + lib/modules/cm_module/cm_detail_page.dart | 149 ++++++++++++++++- .../provider/export_provider.dart | 151 ++++++++++++++++++ 4 files changed, 335 insertions(+), 3 deletions(-) diff --git a/lib/controllers/api_routes/api_manager.dart b/lib/controllers/api_routes/api_manager.dart index abd554d4..9e467199 100644 --- a/lib/controllers/api_routes/api_manager.dart +++ b/lib/controllers/api_routes/api_manager.dart @@ -197,6 +197,40 @@ class ApiManager { return streamedResponse; } + /// POST FormData request that returns StreamedResponse for progress tracking + /// This method is specifically for form-data requests (multipart/form-data) + Future postFormDataStreaming(String url, {Map? headers, required Map body}) async { + // Create headers for form data + Map formHeaders = { + 'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first, + if (user != null) 'Authorization': 'Bearer ${user!.token}', + if (assetGroup != null) 'AssetGroup': assetGroup!.id.toString(), + }; + + headers ??= {}; + headers.addAll(formHeaders); + + Uri url0 = Uri.parse(url); + if (!kReleaseMode) { + print("URL:$url0"); + print("Headers:$headers"); + print("FormData Body:$body"); + } + + var request = http.MultipartRequest('POST', url0); + request.fields.addAll(body); + request.headers.addAll(headers); + + http.StreamedResponse streamedResponse = await _httpClient.send(request); + + // Handle 401 immediately + if (streamedResponse.statusCode == 401) { + showLoginDialog(); + } + + return streamedResponse; + } + Future delete(String url, {Map? headers, required Map body}) async { headers ??= {}; diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index a400d6f3..c6a249ed 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -556,5 +556,9 @@ class URLs { static get getAllWorkOrderColumnsMetadata => "$_baseUrl/CallRequest/columns/metadata"; static get exportAllWorkOrder => "$_baseUrl/CallRequest/Export"; + + // Print/Report URLs + static get generateReport => "$_baseUrl/ReportPDF/GenerateReport"; + //4104 attachment type lookup } diff --git a/lib/modules/cm_module/cm_detail_page.dart b/lib/modules/cm_module/cm_detail_page.dart index 452f3138..b42dca49 100644 --- a/lib/modules/cm_module/cm_detail_page.dart +++ b/lib/modules/cm_module/cm_detail_page.dart @@ -1,9 +1,11 @@ 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'; 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'; @@ -12,16 +14,18 @@ import 'package:test_sa/models/enums/work_order_next_step.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/modules/cm_module/cm_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; -import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; 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/cx_module/survey/survey_page.dart'; +import 'package:test_sa/modules/export_module/provider/export_provider.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:test_sa/views/widgets/loaders/no_data_found.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'; @@ -170,6 +174,11 @@ class _CMDetailPageState extends State { return const SizedBox(); } }), + // Print Button + IconButton( + icon: const Icon(Icons.print), + onPressed: _handlePrint, + ), IconButton( icon: const Icon(Icons.home), onPressed: () { @@ -237,4 +246,138 @@ 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 { + final exportProvider = Provider.of(context, listen: false); + + final filePath = await exportProvider.printWorkOrder( + widget.requestId, + widget.moduleId, + context, + ); + + if (filePath != null) { + await _showSuccessDialog(filePath); + } else if (exportProvider.errorMessage != null) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(exportProvider.errorMessage!), + backgroundColor: AppColor.red60, + ), + ); + } + } + } catch (error) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Print failed: $error'), + backgroundColor: AppColor.red60, + ), + ); + } + } + } } diff --git a/lib/modules/export_module/provider/export_provider.dart b/lib/modules/export_module/provider/export_provider.dart index fde94ecf..b6f5a486 100644 --- a/lib/modules/export_module/provider/export_provider.dart +++ b/lib/modules/export_module/provider/export_provider.dart @@ -240,4 +240,155 @@ class ExportApiProvider extends ChangeNotifier { _errorMessage = null; notifyListeners(); } + + /// Print work order data as PDF + Future printWorkOrder(int workOrderId, int moduleId, BuildContext context) async { + _isExporting = true; + _errorMessage = null; + notifyListeners(); + + ProgressDialog pd = ProgressDialog(context: context); + pd.show( + max: 100, + msg: 'Preparing print...', + progressBgColor: Colors.transparent, + progressValueColor: AppColor.primary10, + msgFontWeight: FontWeight.normal, + valueColor: AppColor.primary10, + ); + + IOSink? sink; + File? outputFile; + + try { + if (!context.mounted) return null; + pd.update(msg: 'Sending print request...'); + log('📡 Sending print request...'); + + final startTime = DateTime.now(); + + // Prepare form data + final Map formData = { + 'properties': json.encode({ + 'workOrderId': workOrderId, + 'moduleId': moduleId, + }), + }; + + final streamedResponse = await ApiManager.instance.postFormDataStreaming( + URLs.generateReport, + body: formData + ); + + _stateCode = streamedResponse.statusCode; + + final responseTime = DateTime.now().difference(startTime).inMilliseconds; + log('✅ Print response received in ${responseTime}ms - Status: ${streamedResponse.statusCode}'); + + if (streamedResponse.statusCode >= 200 && streamedResponse.statusCode < 300) { + final contentLength = streamedResponse.contentLength ?? 0; + log('📊 Content length: ${contentLength > 0 ? "${(contentLength / 1024 / 1024).toStringAsFixed(2)} MB" : "Unknown"}'); + + if (!context.mounted) { + await streamedResponse.stream.drain(); + return null; + } + + final String dir = (await getApplicationDocumentsDirectory()).path; + final String filePath = "$dir/print_${DateTime.now().millisecondsSinceEpoch}.pdf"; + outputFile = File(filePath); + sink = outputFile.openWrite(); + + int received = 0; + int lastProgress = 15; + final downloadStartTime = DateTime.now(); + pd.update(value: 15, msg: 'Generating PDF...'); + + await for (var chunk in streamedResponse.stream) { + sink.add(chunk); + received += chunk.length; + + if (!context.mounted) { + await sink.close(); + await outputFile.delete(); + return null; + } + + if (contentLength > 0) { + final progress = (15 + ((received / contentLength) * 70)).clamp(15, 85).toInt(); + if (progress > lastProgress) { + lastProgress = progress; + final downloadedMB = (received / 1024 / 1024).toStringAsFixed(2); + final totalMB = (contentLength / 1024 / 1024).toStringAsFixed(2); + pd.update( + value: progress, + msg: 'Generating PDF: $downloadedMB MB / $totalMB MB', + ); + } + } else { + final downloadedMB = (received / 1024 / 1024).toStringAsFixed(2); + pd.update( + msg: 'Generating PDF: $downloadedMB MB', + ); + } + } + + await sink.close(); + sink = null; + + final downloadTime = DateTime.now().difference(downloadStartTime).inMilliseconds; + final fileSizeMB = (received / 1024 / 1024).toStringAsFixed(2); + log('✅ PDF generated successfully - Size: ${fileSizeMB} MB'); + + if (!context.mounted) { + await outputFile.delete(); + return null; + } + + pd.close(); + return filePath; + } else { + if (context.mounted) { + pd.close(); + } + try { + final responseBody = await streamedResponse.stream.bytesToString(); + final responseData = json.decode(responseBody); + _errorMessage = responseData['message'] ?? 'Print failed'; + } catch (e) { + log('❌ Error parsing print error response: $e'); + _errorMessage = 'Print failed with status: ${streamedResponse.statusCode}'; + } + return null; + } + } catch (error, stackTrace) { + if (sink != null) { + try { + await sink.close(); + } catch (e) { + log('⚠️ Error closing sink: $e'); + } + } + if (outputFile != null && await outputFile.exists()) { + try { + await outputFile.delete(); + log('🗑️ Deleted incomplete file'); + } catch (e) { + log('⚠️ Error deleting incomplete file: $e'); + } + } + + if (context.mounted) { + pd.close(); + } + log('❌ Error printing data: $error'); + _stateCode = -1; + _errorMessage = 'An error occurred during print: $error'; + return null; + } finally { + _isExporting = false; + notifyListeners(); + log('🔚 Print process finished'); + } + } } From 07560f3b573cd217d0fd6162435254c0927b4d3f Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 6 May 2026 10:21:55 +0300 Subject: [PATCH 2/5] ui changes --- lib/modules/cm_module/cm_detail_page.dart | 18 +++++++++++++----- lib/new_views/app_style/app_color.dart | 7 +++++++ .../land_page/my_request/my_requests_page.dart | 6 +++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/modules/cm_module/cm_detail_page.dart b/lib/modules/cm_module/cm_detail_page.dart index 7059fff1..e6f672fc 100644 --- a/lib/modules/cm_module/cm_detail_page.dart +++ b/lib/modules/cm_module/cm_detail_page.dart @@ -142,11 +142,11 @@ class _CMDetailPageState extends State { return Container( padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), margin: const EdgeInsets.only(left: 2), - decoration: BoxDecoration(color: AppColor.background(context) ,border: Border.all(color: AppColor.border2Color(context)), borderRadius: BorderRadius.circular(16)), + decoration: BoxDecoration(color: AppColor.background(context), border: Border.all(color: AppColor.border2Color(context)), borderRadius: BorderRadius.circular(16)), child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(Icons.add, size: 20, color:AppColor.textStyleColor(context)), + Icon(Icons.add, size: 20, color: AppColor.textStyleColor(context)), Text( "Loan", style: AppTextStyles.bodyText2.copyWith(color: AppColor.textStyleColor(context)), @@ -187,10 +187,14 @@ class _CMDetailPageState extends State { children: [ Container( margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), - decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + decoration: BoxDecoration( + color: AppColor.tabBarBackground(context), + border: Border.all(color: AppColor.tabBarBorder(context)), + borderRadius: BorderRadius.circular(20), + ), child: TabBar( //controller: _tabController, - padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), + padding: EdgeInsets.symmetric(vertical: 6.toScreenHeight, horizontal: 6.toScreenWidth), labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, unselectedLabelStyle: AppTextStyles.bodyText, @@ -198,7 +202,11 @@ class _CMDetailPageState extends State { indicatorPadding: EdgeInsets.zero, indicatorSize: TabBarIndicatorSize.tab, dividerColor: Colors.transparent, - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + overlayColor: WidgetStateProperty.all(Colors.transparent), + indicator: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0)]), onTap: (index) { // setState(() {}); }, diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index 4422e366..e5a249b0 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -96,10 +96,13 @@ class AppColor { static const Color openChartColor = Color(0xff226187); static const Color inProgressChartColor = Color(0xff3DA5E5); static const Color completeChartColor = Color(0xff92D9F8); + static const Color openColor = Color(0xff3DA5E5); static const Color inProgressColor = Color(0xffFDE19B); + static const Color completedColor = Color(0xff54C166); static const Color overdueColor = Color(0xffFFC945); static const Color highPriorityColor = red30; static const Color unassignedColor = Color(0xff9F9FA8); + static const Color lowPriorityColor = Color(0xff54C166); // static Color greenStatus(BuildContext context) => context.isDark ? const Color(0xff1FA269) : green50; static Color greenStatus(BuildContext context) => context.isDark ? const Color(0xff54C166) : green70.withOpacity(.5); @@ -116,6 +119,10 @@ class AppColor { static Color background(BuildContext context) => context.isDark ? containerDark : Colors.white; + static Color tabBarBackground(BuildContext context) => context.isDark ? disableDark : neutral90; + + static Color tabBarBorder(BuildContext context) => context.isDark ? const Color(0xffCCCCCC) : neutral30; + static Color scaffoldBackground(BuildContext context) => context.isDark ? backgroundDark : backgroundLight; static Color dropDownBackground(BuildContext context) => context.isDark ? dropDownDark : backgroundLight; diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index d076a9fb..d0d5a0ee 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -126,7 +126,7 @@ class _MyRequestsPageState extends State { padding: const EdgeInsets.only(left: 16, right: 8), alignment: Alignment.center, decoration: ShapeDecoration( - color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, + color: AppColor.tabBarBackground(context), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), @@ -203,9 +203,9 @@ class _MyRequestsPageState extends State { // ), decoration: ShapeDecoration( color: //selectedRequest == index ? - AppColor.background(context) ,//: AppColor.unSelectedButtonColor(context).withOpacity(snapshot.isAllLoading ? 0.7 : 1), + AppColor.background(context), //: AppColor.unSelectedButtonColor(context).withOpacity(snapshot.isAllLoading ? 0.7 : 1), shape: RoundedRectangleBorder( - side: BorderSide(width: 1, color: selectedRequest == index ? AppColor.primary10 : AppColor.borderColor(context)), + side: BorderSide(width: 1, color: selectedRequest == index ? AppColor.primary10 : AppColor.borderColor(context)), borderRadius: BorderRadius.circular(6), ), shadows: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 14, offset: const Offset(0, 0), spreadRadius: 0)], From 252a03b219e921328537a31f2bd4b0b2dbbd03c7 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 6 May 2026 11:06:20 +0300 Subject: [PATCH 3/5] ui changes --- .../action_button/footer_action_button.dart | 5 +- .../service_request_detail_view.dart | 70 +++++++++---------- .../my_request/my_requests_page.dart | 5 +- .../equipment/single_device_picker.dart | 5 +- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/lib/modules/cm_module/views/components/action_button/footer_action_button.dart b/lib/modules/cm_module/views/components/action_button/footer_action_button.dart index 64587e8a..9835c733 100644 --- a/lib/modules/cm_module/views/components/action_button/footer_action_button.dart +++ b/lib/modules/cm_module/views/components/action_button/footer_action_button.dart @@ -35,7 +35,7 @@ class FooterActionButton { static Widget footerContainer({required Widget child, required BuildContext context}) { return Container( alignment: Alignment.bottomCenter, - padding: const EdgeInsets.only(left: 16, right: 16, top: 12, bottom: 8), + padding: const EdgeInsets.only(left: 16, right: 16, top: 12, bottom: 12), color: AppColor.background(context), child: SafeArea(child: child), ); @@ -216,8 +216,7 @@ class FooterActionButton { children: [ AppFilledButton( label: context.translation.activities, - textColor: context.isDark ? AppColor.black10 : Colors.white, - buttonColor: context.isDark ? AppColor.primary10 : AppColor.neutral50, + buttonColor: AppColor.primary10, onPressed: () async { // ServiceRequestBottomSheet.activityTypeBottomSheet(context: context); Navigator.push(context, MaterialPageRoute(builder: (context) => const ActivitiesListView())); diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart index ca3dff26..e61a2591 100644 --- a/lib/modules/cm_module/views/components/service_request_detail_view.dart +++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart @@ -73,43 +73,43 @@ class _ServiceRequestDetailViewState extends State { : requestProvider.currentWorkOrder == null ? const NoDataFound() : Column( - children: [ - SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider), - initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider), - 12.height, - assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider), - 12.height, - if (context.userProvider.user!.type == UsersTypes.engineer && - !requestProvider.isReadOnlyRequest && - requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[ - costCard(context, requestProvider), + children: [ + SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider), + initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider), + 12.height, + assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider), 12.height, + if (context.userProvider.user!.type == UsersTypes.engineer && + !requestProvider.isReadOnlyRequest && + requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[ + costCard(context, requestProvider), + 12.height, + ], + contactInfoCard(context, requestProvider.currentWorkOrder!.data!), + 20.height, ], - contactInfoCard(context, requestProvider.currentWorkOrder!.data!), - 20.height, - ], - ), - ).expanded, - SafeArea( - top: false, - right: false, - left: false, - child: FooterActionButton.requestDetailsFooterWidget( - workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!, - status: requestProvider.currentWorkOrder?.data?.status, - isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null, - activities: requestProvider.currentWorkOrder!.data?.activities ?? [], - userProvider: _userProvider, - context: context), - ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), - ], - ); + ), + ).expanded, + SafeArea( + top: false, + right: false, + left: false, + child: FooterActionButton.requestDetailsFooterWidget( + workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!, + status: requestProvider.currentWorkOrder?.data?.status, + isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null, + activities: requestProvider.currentWorkOrder!.data?.activities ?? [], + userProvider: _userProvider, + context: context), + ) + ], + ); }); } diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index d0d5a0ee..69fcb175 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -126,9 +126,10 @@ class _MyRequestsPageState extends State { padding: const EdgeInsets.only(left: 16, right: 8), alignment: Alignment.center, decoration: ShapeDecoration( - color: AppColor.tabBarBackground(context), + color: AppColor.dropDownBackground(context), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(6), + side: BorderSide(color: AppColor.borderColor(context)), ), ), child: Row( diff --git a/lib/views/widgets/equipment/single_device_picker.dart b/lib/views/widgets/equipment/single_device_picker.dart index 20f3516e..652c98c6 100644 --- a/lib/views/widgets/equipment/single_device_picker.dart +++ b/lib/views/widgets/equipment/single_device_picker.dart @@ -97,9 +97,10 @@ class _MyAssetsPageState extends State { padding: const EdgeInsets.only(left: 16, right: 8), alignment: Alignment.center, decoration: ShapeDecoration( - color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, + color: AppColor.dropDownBackground(context), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(6), + side: BorderSide(color: AppColor.borderColor(context)), ), ), child: Row( From 7f993490679a84bec214ab044fe9f5af41e4dbaf Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 6 May 2026 11:12:45 +0300 Subject: [PATCH 4/5] tab bar ui changes --- .../pages/asset_delivery_stage_tab_page.dart | 13 ++++++++++--- .../pages/asset_inventory_page.dart | 12 ++++++++++-- .../maintenance_request_main.dart | 12 +++++++----- .../loan_module/pages/pullout_detail_page.dart | 12 ++++++++++-- .../pm_module/ppm_wo/update_ppm/update_ppm.dart | 12 +++++++----- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart index 959beffc..47c0c51c 100644 --- a/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart +++ b/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart @@ -42,7 +42,11 @@ class _AssetDeliveryStageTabPageState extends State { children: [ Container( margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), - decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + decoration: BoxDecoration( + color: AppColor.tabBarBackground(context), + border: Border.all(color: AppColor.tabBarBorder(context)), + borderRadius: BorderRadius.circular(20), + ), child: TabBar( padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, @@ -52,7 +56,11 @@ class _AssetDeliveryStageTabPageState extends State { indicatorPadding: EdgeInsets.zero, indicatorSize: TabBarIndicatorSize.tab, dividerColor: Colors.transparent, - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + overlayColor: WidgetStateProperty.all(Colors.transparent), + indicator: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0)]), tabs: [ Tab(text: context.translation.details, height: 57.toScreenHeight), Tab(text: context.translation.historyLogs, height: 57.toScreenHeight), @@ -73,7 +81,6 @@ class _AssetDeliveryStageTabPageState extends State { )); } - String getPageTitle({AssetDeliveryStageEnum? deliveryStage}) { if (deliveryStage == AssetDeliveryStageEnum.deliveryInspection) { return 'Delivery Inspection'.addTranslation; diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart index f48ff848..f33b961f 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -77,7 +77,11 @@ class _AssetInventoryPageState extends State { children: [ Container( margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), - decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + decoration: BoxDecoration( + color: AppColor.tabBarBackground(context), + border: Border.all(color: AppColor.tabBarBorder(context)), + borderRadius: BorderRadius.circular(20), + ), child: TabBar( padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, @@ -87,7 +91,11 @@ class _AssetInventoryPageState extends State { indicatorPadding: EdgeInsets.zero, indicatorSize: TabBarIndicatorSize.tab, dividerColor: Colors.transparent, - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + overlayColor: WidgetStateProperty.all(Colors.transparent), + indicator: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0)]), onTap: (index) {}, tabs: [ Tab(text: 'Session Details'.addTranslation, height: 57.toScreenHeight), diff --git a/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart b/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart index af231ecd..1fdbea57 100644 --- a/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart +++ b/lib/modules/cm_module/views/forms/maintenance_request/maintenance_request_main.dart @@ -70,8 +70,9 @@ class _MaintenanceRequestFormState extends State with Si Container( margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), decoration: BoxDecoration( - color: context.isDark ? AppColor.neutral50 : AppColor.white10, - borderRadius: BorderRadius.circular(10), + color: AppColor.tabBarBackground(context), + border: Border.all(color: AppColor.tabBarBorder(context)), + borderRadius: BorderRadius.circular(20), ), child: TabBar( padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), @@ -82,10 +83,11 @@ class _MaintenanceRequestFormState extends State with Si indicatorPadding: EdgeInsets.zero, indicatorSize: TabBarIndicatorSize.tab, dividerColor: Colors.transparent, + overlayColor: WidgetStateProperty.all(Colors.transparent), indicator: BoxDecoration( - color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, - borderRadius: BorderRadius.circular(7), - ), + color: AppColor.background(context), + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0)]), tabs: [ Tab(text: context.translation.internal, height: 57.toScreenHeight), Tab(text: context.translation.external, height: 57.toScreenHeight), diff --git a/lib/modules/loan_module/pages/pullout_detail_page.dart b/lib/modules/loan_module/pages/pullout_detail_page.dart index 9992ba8c..a2b95fea 100644 --- a/lib/modules/loan_module/pages/pullout_detail_page.dart +++ b/lib/modules/loan_module/pages/pullout_detail_page.dart @@ -29,7 +29,11 @@ class PullOutDetailsPage extends StatelessWidget { children: [ Container( margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), - decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)), + decoration: BoxDecoration( + color: AppColor.tabBarBackground(context), + border: Border.all(color: AppColor.tabBarBorder(context)), + borderRadius: BorderRadius.circular(20), + ), child: TabBar( padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, @@ -39,7 +43,11 @@ class PullOutDetailsPage extends StatelessWidget { indicatorPadding: EdgeInsets.zero, indicatorSize: TabBarIndicatorSize.tab, dividerColor: Colors.transparent, - indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), + overlayColor: WidgetStateProperty.all(Colors.transparent), + indicator: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0)]), onTap: (index) { // setState(() {}); }, diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart index 0c375db8..a61a8efd 100644 --- a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart +++ b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart @@ -148,8 +148,9 @@ class _UpdatePpmState extends State with TickerProviderStateMixin { Container( margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 16.toScreenHeight, bottom: 8), decoration: BoxDecoration( - color: context.isDark ? AppColor.neutral50 : AppColor.white10, - borderRadius: BorderRadius.circular(10), + color: AppColor.tabBarBackground(context), + border: Border.all(color: AppColor.tabBarBorder(context)), + borderRadius: BorderRadius.circular(20), ), child: TabBar( padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), @@ -160,10 +161,11 @@ class _UpdatePpmState extends State with TickerProviderStateMixin { indicatorPadding: EdgeInsets.zero, indicatorSize: TabBarIndicatorSize.tab, dividerColor: Colors.transparent, + overlayColor: WidgetStateProperty.all(Colors.transparent), indicator: BoxDecoration( - color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, - borderRadius: BorderRadius.circular(7), - ), + color: AppColor.background(context), + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0)]), onTap: (index) { tabIndex = index; if (tabIndex == 0) { From fc66e2dd8ab5fd8bf055b326ab512d4a7b51772a Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 6 May 2026 12:26:26 +0300 Subject: [PATCH 5/5] swipe view ui changes --- .../common_widgets/app_filled_button.dart | 2 +- .../swipe_module/swipe_history_view.dart | 63 +++++++++---------- .../swipe_module/swipe_success_view.dart | 20 +++--- 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/lib/new_views/common_widgets/app_filled_button.dart b/lib/new_views/common_widgets/app_filled_button.dart index 1ab0daf5..905516fc 100644 --- a/lib/new_views/common_widgets/app_filled_button.dart +++ b/lib/new_views/common_widgets/app_filled_button.dart @@ -47,7 +47,7 @@ class AppFilledButton extends StatelessWidget { alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: disableButton ?context.isDark ?AppColor.neutral20 :AppColor.neutral140 : (buttonColor ?? AppColor.blueStatus(context)), + color: disableButton ?context.isDark ?AppColor.neutral20 :AppColor.neutral140 : (buttonColor ?? AppColor.primary10), border: showBorder ? Border.all(color: textColor ?? AppColor.background(context)) : null, ), child: loading diff --git a/lib/new_views/swipe_module/swipe_history_view.dart b/lib/new_views/swipe_module/swipe_history_view.dart index 5dbc1865..bd834a70 100644 --- a/lib/new_views/swipe_module/swipe_history_view.dart +++ b/lib/new_views/swipe_module/swipe_history_view.dart @@ -13,7 +13,6 @@ import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; - import 'models/swipe_transaction_history.dart'; class SwipeHistoryView extends StatefulWidget { @@ -25,31 +24,33 @@ class SwipeHistoryView extends StatefulWidget { State createState() => _SwipeHistoryViewState(); } - class _SwipeHistoryViewState extends State { DateTime dateFrom = DateTime.now(); DateTime dateTo = DateTime.now(); UserProvider? _userProvider; + @override void initState() { getSwipeHistory(); super.initState(); } - void getSwipeHistory () { - _userProvider = Provider.of(context,listen:false); + void getSwipeHistory() { + _userProvider = Provider.of(context, listen: false); WidgetsBinding.instance.addPostFrameCallback((_) async { - await _userProvider!.getSwipeTransactionHistory(userId: _userProvider!.user!.userID!,dateFrom: dateFrom,dateTo: dateTo); + await _userProvider!.getSwipeTransactionHistory(userId: _userProvider!.user!.userID!, dateFrom: dateFrom, dateTo: dateTo); }); } + @override Widget build(BuildContext context) { - return Scaffold( - appBar: const DefaultAppBar(title: 'Swipe History',), + return Scaffold( + appBar: const DefaultAppBar( + title: 'Swipe History', + ), body: Column( - crossAxisAlignment:CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - 8.height, Row( children: [ @@ -106,10 +107,8 @@ class _SwipeHistoryViewState extends State { ); if (selectedDateTime != null) { setState(() { - dateTo = selectedDateTime; - + dateTo = selectedDateTime; }); - } } }); @@ -121,48 +120,46 @@ class _SwipeHistoryViewState extends State { 12.height, AppFilledButton(label: context.translation.search, maxWidth: false, onPressed: getSwipeHistory), 8.height, - const Divider(thickness: 2,color:AppColor.white60 ,), - - Consumer( - builder: (context, snapshot,child) { - return SwipeHistoryList(snapshot.swipeHistory ?? [], snapshot.isLoading).expanded; - } + const Divider( + thickness: 2, + color: AppColor.white60, ), - - + Consumer(builder: (context, snapshot, child) { + return SwipeHistoryList(snapshot.swipeHistory ?? [], snapshot.isLoading).expanded; + }), ], ).paddingAll(20), ); } } - - - class SwipeHistoryList extends StatelessWidget { List list; bool isLoading; - SwipeHistoryList(this.list, this.isLoading, {Key ?key}) : super(key: key); + SwipeHistoryList(this.list, this.isLoading, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return (list.isEmpty && !isLoading) ? NoDataFound(message: context.translation.noDataFound).center : ListView.separated( - padding: EdgeInsets.only(top: 12.toScreenHeight), - itemBuilder: (cxt, index) { - if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); - return SwipeHistoryCard(list[index]); - }, - separatorBuilder: (cxt, index) => 12.height, - itemCount: isLoading ? 6 : list.length); + padding: EdgeInsets.only(top: 12.toScreenHeight), + itemBuilder: (cxt, index) { + if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); + return SwipeHistoryCard(list[index]); + }, + separatorBuilder: (cxt, index) => 12.height, + itemCount: isLoading ? 6 : list.length); } } + class SwipeHistoryCard extends StatelessWidget { final SwipeHistory swipeHistory; final bool showShadow; + const SwipeHistoryCard(this.swipeHistory, {Key? key, this.showShadow = true}) : super(key: key); + @override Widget build(BuildContext context) { return Column( @@ -172,7 +169,8 @@ class SwipeHistoryCard extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(swipeHistory.swipeTime!.toServiceRequestDetailsFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50)), + Text(swipeHistory.swipeTime!.toServiceRequestDetailsFormat, + textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50)), ], ), 8.height, @@ -185,4 +183,3 @@ class SwipeHistoryCard extends StatelessWidget { ).toShadowContainer(context, showShadow: showShadow); } } - diff --git a/lib/new_views/swipe_module/swipe_success_view.dart b/lib/new_views/swipe_module/swipe_success_view.dart index 2a85cd1e..96b40979 100644 --- a/lib/new_views/swipe_module/swipe_success_view.dart +++ b/lib/new_views/swipe_module/swipe_success_view.dart @@ -8,29 +8,36 @@ import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; class SwipeSuccessView extends StatelessWidget { static const routeName = '/swipe_success_view'; - const SwipeSuccessView({Key ?key}) : super(key: key); + + const SwipeSuccessView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return Scaffold( + return Scaffold( body: SafeArea( child: Column( children: [ Column( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment:CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ 'swipe_success'.toSvgAsset(), 17.height, - context.translation.successful.heading4(context).custom(color: AppColor.white936), + Text( + context.translation.successful, + style: AppTextStyles.heading4.copyWith(color: AppColor.headingTextColor(context)), + ), 8.height, - context.translation.youHaveSuccessfullyMarkedYourAttendance.bodyText2(context).custom(color: AppColor.neutral120), + Text( + context.translation.youHaveSuccessfullyMarkedYourAttendance, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.lightTextColor(context)), + ), ], ).expanded, AppFilledButton( label: 'Close', maxWidth: true, - onPressed:(){ + onPressed: () { Navigator.pop(context); }, ), @@ -41,7 +48,6 @@ class SwipeSuccessView extends StatelessWidget { } } - // ClipOval( // child: Container( // color: Colors.grey.withOpacity(0.2),