From 023a47f69f05c51e0126711439076c28282d5d15 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 26 Apr 2026 16:18:07 +0300 Subject: [PATCH] recurrent task, cleaner improvements. --- lib/extensions/widget_extensions.dart | 3 +- .../pages/cleaner_search_details_view.dart | 94 ++--- .../widgets/cleaner_checklist_widget.dart | 352 +++++++++++------- .../components/task_info_widget.dart | 12 +- .../recurrent_work_order_view.dart | 134 ++++--- 5 files changed, 331 insertions(+), 264 deletions(-) diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 7b468913..252971f7 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -15,6 +15,8 @@ extension WidgetExtensions on Widget { Widget get center => Center(child: this); + Widget ignorePointer(bool value) => IgnorePointer(ignoring: value, child: this); + BoxShadow get boxShadowR14 => BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0); Widget circle(double value) => ClipRRect(borderRadius: BorderRadius.circular(value), child: this); @@ -202,4 +204,3 @@ extension WidgetExtensions on Widget { extension DividerExtension on Divider { Divider defaultStyle(BuildContext context) => Divider(thickness: 1, color: context.isDarkNotListen ? AppColor.neutral20 : AppColor.neutral30); } - diff --git a/lib/modules/cleaner_module/pages/cleaner_search_details_view.dart b/lib/modules/cleaner_module/pages/cleaner_search_details_view.dart index 948688d0..65d7b525 100644 --- a/lib/modules/cleaner_module/pages/cleaner_search_details_view.dart +++ b/lib/modules/cleaner_module/pages/cleaner_search_details_view.dart @@ -70,7 +70,7 @@ class _CleanerSearchDetailsViewState extends State { floorName: recurrentData.floor?.name, departmentName: recurrentData.department?.name, roomName: recurrentData.room?.name, - locationDescription: null, // Not available in RecurrentWoData + locationDescription: null, createdDate: recurrentData.scheduleDate, ); } @@ -101,51 +101,40 @@ class _CleanerSearchDetailsViewState extends State { ), body: _isLoading ? const Center(child: CircularProgressIndicator()) - : Selector( - selector: (_, model) => model.isLoading, - builder: (_, isLoading, __) { - if (isLoading) { - return const Center(child: CircularProgressIndicator()); - } + : SafeArea( + child: Selector( + selector: (_, model) => model.isLoading, + builder: (_, isLoading, __) { + if (isLoading) { + return const Center(child: CircularProgressIndicator()); + } - return Column( - children: [ - Expanded( - child: SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + return Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - 18.height, _buildCleanerRequestDetailCard(context), - 20.height, ], ), - ), - ), - SafeArea( - top: false, - right: false, - left: false, - child: FooterActionButton.footerContainer( + ).expanded, + FooterActionButton.footerContainer( context: context, child: Column( mainAxisSize: MainAxisSize.min, children: [ - if (!_isQRScanned) + if (!_isQRScanned) ...[ Row( children: [ - Icon( - Icons.info_outline, - color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, - size: 15, - ), + Icon(Icons.info_outline_rounded, size: 16, color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), 8.width, Expanded( child: Text( 'By scanning the QR code you will accept this task'.addTranslation, - textAlign: TextAlign.center, + // textAlign: TextAlign.center, style: AppTextStyles.bodyText.copyWith( color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, ), @@ -153,7 +142,8 @@ class _CleanerSearchDetailsViewState extends State { ), ], ), - 16.height, + 8.height, + ], AppFilledButton( label: _isQRScanned ? 'Update' : 'Scan QR Code', maxWidth: true, @@ -206,12 +196,12 @@ class _CleanerSearchDetailsViewState extends State { }, ), ], - ).paddingOnly(start: 16, end: 16), - ), - ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), - ], - ); - }, + ), + ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + ], + ); + }, + ), ), ); } @@ -248,11 +238,9 @@ class _CleanerSearchDetailsViewState extends State { ), if (taskResult.createdDate != null) Text( - taskResult.createdDate!.split('T').first, + taskResult.createdDate!.toServiceRequestCardFormat, textAlign: TextAlign.end, - style: AppTextStyles.tinyFont.copyWith( - color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, - ), + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), ], ), @@ -260,51 +248,37 @@ class _CleanerSearchDetailsViewState extends State { if (taskResult.taskNo != null && taskResult.taskNo!.isNotEmpty) Text( 'Task No: ${taskResult.taskNo!}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), if (taskResult.siteName != null && taskResult.siteName!.isNotEmpty) Text( 'Site: ${taskResult.siteName}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), if (taskResult.buildingName != null && taskResult.buildingName!.isNotEmpty) Text( 'Building: ${taskResult.buildingName}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), if (taskResult.floorName != null && taskResult.floorName!.isNotEmpty) Text( 'Floor: ${taskResult.floorName}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), if (taskResult.departmentName != null && taskResult.departmentName!.isNotEmpty) Text( 'Department: ${taskResult.departmentName}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), if (taskResult.roomName != null && taskResult.roomName!.isNotEmpty) Text( 'Room: ${taskResult.roomName}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), if (taskResult.locationDescription != null && taskResult.locationDescription!.isNotEmpty) Text( 'Location: ${taskResult.locationDescription}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], ).expanded, diff --git a/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart b/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart index 0e8d9de0..9f6f117b 100644 --- a/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart +++ b/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart @@ -12,20 +12,16 @@ 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_text_form_field.dart'; +import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; class CleanerChecklistWidget extends StatefulWidget { final List checklistItems; final Function(List)? onChecklistChanged; final String? capturedImageBase64; final Function(String?)? onImageCaptured; + bool isClosed; - const CleanerChecklistWidget({ - Key? key, - required this.checklistItems, - this.onChecklistChanged, - this.capturedImageBase64, - this.onImageCaptured, - }) : super(key: key); + CleanerChecklistWidget({Key? key, required this.checklistItems, this.onChecklistChanged, this.capturedImageBase64, this.onImageCaptured, this.isClosed = false}) : super(key: key); @override State createState() => _CleanerChecklistWidgetState(); @@ -50,82 +46,88 @@ class _CleanerChecklistWidgetState extends State { ), 16.height, ...widget.checklistItems.map((item) => _buildChecklistItem(context, item)).toList(), - 16.height, + // 16.height, _buildImageCaptureWidget(context), ], ); } Widget _buildChecklistItem(BuildContext context, ChecklistItem item) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Checkbox with title - Row( - children: [ - Checkbox( - value: item.isChecked, - activeColor: AppColor.primary10, - onChanged: (bool? value) { - setState(() { - item.isChecked = value ?? false; - if (!item.isChecked) { - item.commentController.clear(); - } - }); - // Notify parent of changes - widget.onChecklistChanged?.call(widget.checklistItems); - }, - ), - 8.width, - Expanded( - child: RichText( - text: TextSpan( - children: [ - TextSpan( - text: item.title, - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - fontWeight: FontWeight.w600, - ), - ), - if (item.isMandatory) + return IgnorePointer( + ignoring: widget.isClosed, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // Checkbox with title + Row( + children: [ + Checkbox( + // visualDensity: const VisualDensity(horizontal: -4.0, vertical: -4.0), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + value: item.isChecked, + activeColor: AppColor.primary10, + onChanged: (bool? value) { + setState(() { + item.isChecked = value ?? false; + if (!item.isChecked) { + item.commentController.clear(); + } + }); + // Notify parent of changes + widget.onChecklistChanged?.call(widget.checklistItems); + }, + ), + 8.width, + Expanded( + child: RichText( + text: TextSpan( + children: [ TextSpan( - text: ' *', + text: item.title, style: AppTextStyles.bodyText.copyWith( - color: Colors.red, - fontWeight: FontWeight.w600, + color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, + fontWeight: FontWeight.w500, ), ), - ], + if (item.isMandatory) + TextSpan( + text: ' *', + style: AppTextStyles.bodyText.copyWith( + color: Colors.red, + fontWeight: FontWeight.w500, + ), + ), + ], + ), ), ), - ), - ], - ), + ], + ), - // Comment box - only visible when checked - if (item.isChecked) ...[ - 16.height, - AppTextFormField( - controller: item.commentController, - labelText: context.translation.comment, - backgroundColor: AppColor.fieldBgColor(context), - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle.copyWith( - color: context.isDark ? AppColor.white10 : AppColor.black10, + // Comment box - only visible when checked + if (item.isChecked) ...[ + 16.height, + AppTextFormField( + controller: item.commentController, + labelText: context.translation.comment, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith( + color: context.isDark ? AppColor.white10 : AppColor.black10, + ), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) { + item.comment = value; + // Notify parent of changes + widget.onChecklistChanged?.call(widget.checklistItems); + }, ), - alignLabelWithHint: true, - textInputType: TextInputType.multiline, - onChange: (value) { - item.comment = value; - // Notify parent of changes - widget.onChecklistChanged?.call(widget.checklistItems); - }, - ), + ], ], - ], - ).toShadowContainer(context).paddingOnly(bottom: 16); + ).toShadowContainer(context).paddingOnly(bottom: 16), + ); } Widget _buildImageCaptureWidget(BuildContext context) { @@ -140,26 +142,7 @@ class _CleanerChecklistWidgetState extends State { ), ), 8.height, - GestureDetector( - onTap: () async { - // Image capture logic - final pickedFile = await ImagePicker().pickImage(source: ImageSource.camera); - if (pickedFile != null) { - // Convert image to Base64 with filename prefix (same format as CM request) - final bytes = await pickedFile.readAsBytes(); - final base64Image = base64Encode(bytes); - final fileName = pickedFile.path.split("/").last; - final formattedImage = "$fileName|$base64Image"; - - // Update parent with captured image - widget.onImageCaptured?.call(formattedImage); - } - }, - child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: _buildImageWidget(context), - ), - ), + _buildImageWidget(context), ], ).toShadowContainer(context); } @@ -180,9 +163,23 @@ class _CleanerChecklistWidgetState extends State { size: 48, color: context.isDark ? AppColor.white10 : AppColor.black10, ), - ); + ).onPress(() async { + final pickedFile = await ImagePicker().pickImage(source: ImageSource.camera, imageQuality: 70, maxWidth: 800, maxHeight: 800); + if (pickedFile != null) { + // Convert image to Base64 with filename prefix (same format as CM request) + final bytes = await pickedFile.readAsBytes(); + final base64Image = base64Encode(bytes); + final fileName = pickedFile.path.split("/").last; + final formattedImage = "$fileName|$base64Image"; + + // Update parent with captured image + widget.onImageCaptured?.call(formattedImage); + } + }); } + Widget imageWidget; + final imageString = widget.capturedImageBase64!; // First check if it's base64 encoded (contains | separator) @@ -190,17 +187,37 @@ class _CleanerChecklistWidgetState extends State { // Format: "filename|base64data" try { final base64Data = imageString.split('|').last; - return Container( - height: 200, - width: double.infinity, - decoration: BoxDecoration( - color: AppColor.fieldBgColor(context), - borderRadius: BorderRadius.circular(8), - ), - child: Image.memory( - base64Decode(base64Data), - fit: BoxFit.cover, - ), + imageWidget = Image.memory(base64Decode(base64Data), fit: BoxFit.cover); + return Stack( + alignment: AlignmentDirectional.topEnd, + children: [ + Container( + height: 200, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(8), + ), + child: imageWidget) + .onPress(() { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + body: SafeArea( + child: Stack( + children: [ + // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, + InteractiveViewer(child: imageWidget).center, + const ABackButton(), + ], + ), + ), + ), + ), + ); + }), + _delete(), + ], ); } catch (e) { debugPrint('Error decoding base64 image: $e'); @@ -211,17 +228,37 @@ class _CleanerChecklistWidgetState extends State { // Check if it's a local file path if (_isLocalUrl(imageString)) { try { - return Container( - height: 200, - width: double.infinity, - decoration: BoxDecoration( - color: AppColor.fieldBgColor(context), - borderRadius: BorderRadius.circular(8), - ), - child: Image.file( - File(imageString), - fit: BoxFit.cover, - ), + imageWidget = Image.file(File(imageString), fit: BoxFit.cover); + return Stack( + alignment: AlignmentDirectional.topEnd, + children: [ + Container( + height: 200, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(8), + ), + child: imageWidget) + .onPress(() { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + body: SafeArea( + child: Stack( + children: [ + // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, + InteractiveViewer(child: imageWidget).center, + const ABackButton(), + ], + ), + ), + ), + ), + ); + }), + _delete(), + ], ); } catch (e) { debugPrint('Error loading local file: $e'); @@ -232,34 +269,55 @@ class _CleanerChecklistWidgetState extends State { // If not local and not base64, it's a server filename - use NetworkImage with loading indicator final imageUrl = URLs.getFileUrl(imageString); if (imageUrl != null) { - return Container( - height: 200, - width: double.infinity, - decoration: BoxDecoration( - color: AppColor.fieldBgColor(context), - borderRadius: BorderRadius.circular(8), - ), - child: Image.network( - imageUrl, - fit: BoxFit.cover, - loadingBuilder: (context, child, loadingProgress) { - if (loadingProgress == null) { - return child; - } - return Center( - child: CircularProgressIndicator( - color: AppColor.primary10, - value: loadingProgress.expectedTotalBytes != null - ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! - : null, + imageWidget = Image.network( + imageUrl, + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) { + return child; + } + return Center( + child: CircularProgressIndicator( + color: AppColor.primary10, + value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + debugPrint('Error loading network image: $error'); + return _buildCameraIcon(context); + }, + ); + return Stack( + alignment: AlignmentDirectional.topEnd, + children: [ + Container( + height: 200, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(8), + ), + child: imageWidget) + .onPress(() { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + body: SafeArea( + child: Stack( + children: [ + // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, + InteractiveViewer(child: imageWidget).center, + const ABackButton(), + ], + ), + ), + ), ), ); - }, - errorBuilder: (context, error, stackTrace) { - debugPrint('Error loading network image: $error'); - return _buildCameraIcon(context); - }, - ), + }), + _delete(), + ], ); } @@ -295,6 +353,26 @@ class _CleanerChecklistWidgetState extends State { // Note: Don't dispose controllers here as they're managed by ChecklistItem super.dispose(); } + + Widget _delete() { + if (widget.isClosed) return const SizedBox(); + return Container( + height: 45.toScreenHeight, + width: 45.toScreenHeight, + margin: const EdgeInsets.only(top: 4, right: 4), + decoration: BoxDecoration( + color: (context.isDark ? AppColor.neutral20 : AppColor.neutral40).withValues(alpha: 0.4), + border: Border.all( + color: (context.isDark ? AppColor.neutral20 : AppColor.neutral40).withValues(alpha: 0.7), + ), + borderRadius: BorderRadius.circular(30), + //boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + child: const Icon(Icons.delete_rounded, color: Color(0xffF63939))) + .onPress(() { + widget.onImageCaptured?.call(null); + }); + } } /// Model class for checklist items diff --git a/lib/modules/pm_module/recurrent_wo/components/task_info_widget.dart b/lib/modules/pm_module/recurrent_wo/components/task_info_widget.dart index 7b7880ff..22a6477a 100644 --- a/lib/modules/pm_module/recurrent_wo/components/task_info_widget.dart +++ b/lib/modules/pm_module/recurrent_wo/components/task_info_widget.dart @@ -18,8 +18,9 @@ import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart class RecurrentTaskInfoWidget extends StatefulWidget { final RecurrentWoData? model; + bool isClosed; - RecurrentTaskInfoWidget({super.key, required this.model}); + RecurrentTaskInfoWidget({super.key, required this.model, this.isClosed = false}); @override State createState() => _RecurrentTaskInfoWidgetState(); @@ -90,15 +91,16 @@ class _RecurrentTaskInfoWidgetState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - buildingInfoWidget(label: context.translation.department, value: widget.model!.department?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context), + buildingInfoWidget(label: context.translation.department, value: widget.model!.department?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context) + .ignorePointer(widget.isClosed), 8.height, - buildingInfoWidget(label: context.translation.floor, value: widget.model!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context), + buildingInfoWidget(label: context.translation.floor, value: widget.model!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context).ignorePointer(widget.isClosed), 8.height, - buildingInfoWidget(label: context.translation.room, value: widget.model!.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context), + buildingInfoWidget(label: context.translation.room, value: widget.model!.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, context: context).ignorePointer(widget.isClosed), 8.height, _timerWidget(context, totalWorkingHours), 8.height, - _commentWidget(context: context, model: widget.model) + _commentWidget(context: context, model: widget.model).ignorePointer(widget.isClosed), ], // ], ).toShadowContainer(context, padding: 12) diff --git a/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart b/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart index 11853b27..800b19f0 100644 --- a/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart +++ b/lib/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart @@ -50,84 +50,96 @@ class _RecurrentWorkOrderViewState extends State { super.dispose(); } + bool isClosed = false; + @override Widget build(BuildContext context) { return Consumer(builder: (context, requestProvider, child) { + isClosed = requestProvider.recurrentWoData?.status?.value == 1; return Scaffold( appBar: DefaultAppBar( title: context.translation.recurrentWo, - onWillPopScope: () { - _updateTask(context: context, status: 0); - }, + onWillPopScope: isClosed + ? null + : () { + _updateTask(context: context, status: 0); + }, ), body: allRequestsProvider!.isLoading ? const ALoading() : requestProvider.recurrentWoData != null - ? Column( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RecurrentTaskInfoWidget(model: requestProvider.recurrentWoData), - requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms != null && requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms!.isNotEmpty - ? Column( - children: [ - 8.height, - RoomTabsWidget(model: requestProvider.recurrentWoData), - ], - ) - : const SizedBox(), - 16.height, - requestProvider.recurrentWoData!.planRecurrentTaskCheckLists != null && requestProvider.recurrentWoData!.planRecurrentTaskCheckLists!.isNotEmpty - ? CleanerChecklistWidget( - checklistItems: requestProvider.recurrentWoData!.planRecurrentTaskCheckLists ?? [], - onChecklistChanged: (value) { - setState(() { - requestProvider.recurrentWoData!.planRecurrentTaskCheckLists = value; - }); - }, - capturedImageBase64: requestProvider.recurrentWoData!.imageRoom, - onImageCaptured: (imageBase64) { - setState(() { - requestProvider.recurrentWoData!.imageRoom = imageBase64; - }); - }, - ) - : const SizedBox(), - ], - ), - ).expanded, - if (requestProvider.recurrentWoData?.status?.value != 1) ...[ - FooterActionButton.footerContainer( - context: context, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, + ? SafeArea( + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - AppFilledButton( - label: context.translation.save, - buttonColor: context.isDark ? AppColor.neutral20 : AppColor.white60, - textColor: context.isDark ? Colors.white : AppColor.black10, - onPressed: () => _updateTask(context: context, status: 0), - ).expanded, - 12.width, - AppFilledButton( - label: context.translation.complete, - buttonColor: AppColor.primary10, - // textColor: context.isDark?Colors.white: AppColor.black10, - onPressed: () => _updateTask(context: context, status: 1), - ).expanded, + RecurrentTaskInfoWidget(isClosed: isClosed,model: requestProvider.recurrentWoData), + IgnorePointer( + ignoring: isClosed, + child: requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms != null && requestProvider.recurrentWoData!.planRecurrentMedicalTaskRooms!.isNotEmpty + ? Column( + children: [ + 8.height, + RoomTabsWidget(model: requestProvider.recurrentWoData), + ], + ) + : const SizedBox(), + ), + 16.height, + requestProvider.recurrentWoData!.planRecurrentTaskCheckLists != null && requestProvider.recurrentWoData!.planRecurrentTaskCheckLists!.isNotEmpty + ? CleanerChecklistWidget( + isClosed: isClosed, + checklistItems: requestProvider.recurrentWoData!.planRecurrentTaskCheckLists ?? [], + onChecklistChanged: (value) { + setState(() { + requestProvider.recurrentWoData!.planRecurrentTaskCheckLists = value; + }); + }, + capturedImageBase64: requestProvider.recurrentWoData!.imageRoom, + onImageCaptured: (imageBase64) { + setState(() { + requestProvider.recurrentWoData!.imageRoom = imageBase64; + }); + }, + ) + : const SizedBox(), ], ), - ), - ] - ], + ).expanded, + if (requestProvider.recurrentWoData?.status?.value != 1) ...[ + FooterActionButton.footerContainer( + context: context, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + AppFilledButton( + label: context.translation.save, + buttonColor: context.isDark ? AppColor.neutral20 : AppColor.white60, + textColor: context.isDark ? Colors.white : AppColor.black10, + onPressed: () => _updateTask(context: context, status: 0), + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.complete, + buttonColor: AppColor.primary10, + // textColor: context.isDark?Colors.white: AppColor.black10, + onPressed: () => _updateTask(context: context, status: 1), + ).expanded, + ], + ), + ), + ] + ], + ), ) : NoDataFound(message: context.translation.noDataFound).center, ).handlePopScope( cxt: context, + showPopUp: !isClosed, onSave: () { _updateTask(context: context, status: 0); });