diff --git a/lib/app/modules/detailRoute/controllers/detail_route_controller.dart b/lib/app/modules/detailRoute/controllers/detail_route_controller.dart index 4820e881..68f121ca 100644 --- a/lib/app/modules/detailRoute/controllers/detail_route_controller.dart +++ b/lib/app/modules/detailRoute/controllers/detail_route_controller.dart @@ -45,7 +45,9 @@ class DetailRouteController extends GetxController { } modify.set(name, newValue); - onEdit.value = true; + +// onEdit must reflect REAL changes only + onEdit.value = modify.changes.isNotEmpty; // If status is being changed, update read-only state if (name == 'status') { @@ -68,7 +70,7 @@ class DetailRouteController extends GetxController { } var now = DateTime.now().toUtc(); modify.save(modified: () => now); - onEdit.value = false; + onEdit.value = modify.changes.isNotEmpty; // Show snackbar Get.snackbar( diff --git a/lib/app/modules/detailRoute/views/detail_route_view.dart b/lib/app/modules/detailRoute/views/detail_route_view.dart index f62c48a7..b7bed41b 100644 --- a/lib/app/modules/detailRoute/views/detail_route_view.dart +++ b/lib/app/modules/detailRoute/views/detail_route_view.dart @@ -119,122 +119,128 @@ class DetailRouteView extends GetView { return true; }, child: Scaffold( - backgroundColor: tColors.primaryBackgroundColor, - appBar: AppBar( - leading: BackButton(color: TaskWarriorColors.white), - backgroundColor: Palette.kToDark, - title: Text( - '${SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences.detailPageID}: ${(controller.modify.id == 0) ? '-' : controller.modify.id}', - style: TextStyle( - color: TaskWarriorColors.white, - ), - )), - body: Padding( - padding: const EdgeInsets.only(left: 8.0, right: 8.0), - child: Obx( - () => ListView( - padding: - const EdgeInsets.symmetric(vertical: 4, horizontal: 2), - children: [ - for (var entry in { - 'description': controller.descriptionValue.value, - 'status': controller.statusValue.value, - 'entry': controller.entryValue.value, - 'modified': controller.modifiedValue.value, - 'start': controller.startValue.value, - 'end': controller.endValue.value, - 'due': controller.dueValue.value, - 'wait': controller.waitValue.value, - 'until': controller.untilValue.value, - 'priority': controller.priorityValue?.value, - 'project': controller.projectValue?.value, - 'tags': controller.tagsValue?.value, - 'urgency': controller.urgencyValue.value, - }.entries) - AttributeWidget( - name: entry.key, - value: entry.value, - callback: (newValue) => - controller.setAttribute(entry.key, newValue), - waitKey: controller.waitKey, - dueKey: controller.dueKey, - untilKey: controller.untilKey, - priorityKey: controller.priorityKey, - ), - ], - ), - )), - floatingActionButton: controller.modify.changes.isEmpty - ? const SizedBox.shrink() - : FloatingActionButton( - backgroundColor: tColors.primaryTextColor, - foregroundColor: tColors.secondaryBackgroundColor, - splashColor: tColors.primaryTextColor, - heroTag: "btn1", - onPressed: () { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - scrollable: true, - title: Text( - '${SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences.reviewChanges}:', - style: TextStyle( - color: tColors.primaryTextColor, - ), - ), - content: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Text( - controller.modify.changes.entries - .map((entry) => '${entry.key}:\n' - ' ${SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences.oldChanges}: ${entry.value['old']}\n' - ' ${SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences.newChanges}: ${entry.value['new']}') - .toList() - .join('\n'), - style: TextStyle( - color: tColors.primaryTextColor, - ), - ), - ), - actions: [ - TextButton( - onPressed: () { - Get.back(); - }, - child: Text( - SentenceManager( - currentLanguage: - AppSettings.selectedLanguage) - .sentences - .cancel, - style: TextStyle( - color: tColors.primaryTextColor, - ), - ), - ), - TextButton( - onPressed: () { - controller.saveChanges(); - }, - child: Text( - SentenceManager( - currentLanguage: - AppSettings.selectedLanguage) - .sentences - .submit, - style: TextStyle( - color: tColors.primaryBackgroundColor, - ), - ), - ), - ], - ); - }, - ); - }, - child: const Icon(Icons.save), - )), + backgroundColor: tColors.primaryBackgroundColor, + appBar: AppBar( + leading: BackButton(color: TaskWarriorColors.white), + backgroundColor: Palette.kToDark, + title: Text( + '${SentenceManager(currentLanguage: AppSettings.selectedLanguage).sentences.detailPageID}: ${(controller.modify.id == 0) ? '-' : controller.modify.id}', + style: TextStyle( + color: TaskWarriorColors.white, + ), + )), + body: Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0), + child: Obx( + () => ListView( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 2), + children: [ + for (var entry in { + 'description': controller.descriptionValue.value, + 'status': controller.statusValue.value, + 'entry': controller.entryValue.value, + 'modified': controller.modifiedValue.value, + 'start': controller.startValue.value, + 'end': controller.endValue.value, + 'due': controller.dueValue.value, + 'wait': controller.waitValue.value, + 'until': controller.untilValue.value, + 'priority': controller.priorityValue?.value, + 'project': controller.projectValue?.value, + 'tags': controller.tagsValue?.value, + 'urgency': controller.urgencyValue.value, + }.entries) + AttributeWidget( + name: entry.key, + value: entry.value, + callback: (newValue) => + controller.setAttribute(entry.key, newValue), + waitKey: controller.waitKey, + dueKey: controller.dueKey, + untilKey: controller.untilKey, + priorityKey: controller.priorityKey, + ), + ], + ), + )), + + // SAVE BUTTON — Bottom Right + + floatingActionButton: Obx(() { + if (!controller.onEdit.value) { + return const SizedBox.shrink(); + } + + return FloatingActionButton( + onPressed: () => _showReviewChangesDialog(context, tColors), + backgroundColor: tColors.primaryTextColor, + foregroundColor: tColors.secondaryBackgroundColor, + splashColor: tColors.primaryTextColor, + child: const Icon(Icons.save), + ); + }), + floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, + ), + ); + } + + // REVIEW CHANGES DIALOG + void _showReviewChangesDialog( + BuildContext context, TaskwarriorColorTheme tColors) { + final sentences = + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences; + + showDialog( + context: context, + builder: (context) { + return AlertDialog( + scrollable: true, + title: Text( + '${sentences.reviewChanges}:', + style: TextStyle(color: tColors.primaryTextColor), + ), + content: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Text( + controller.modify.changes.entries + .map((entry) => '${entry.key}:\n' + ' ${sentences.oldChanges}: ${entry.value['old']}\n' + ' ${sentences.newChanges}: ${entry.value['new']}') + .toList() + .join('\n'), + style: TextStyle(color: tColors.primaryTextColor), + ), + ), + actions: [ + TextButton( + onPressed: () => Get.back(), + child: Text( + sentences.cancel, + style: TextStyle(color: tColors.primaryTextColor), + ), + ), + TextButton( + onPressed: () { + Get.back(); + controller.saveChanges(); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(sentences.taskUpdated), + behavior: SnackBarBehavior.floating, + duration: const Duration(seconds: 2), + ), + ); + }, + child: Text( + sentences.submit, + style: const TextStyle(color: Colors.white), + ), + ), + ], + ); + }, ); } } diff --git a/lib/app/modules/detailRoute/views/priority_widget.dart b/lib/app/modules/detailRoute/views/priority_widget.dart index 9835ff3c..b14e1821 100644 --- a/lib/app/modules/detailRoute/views/priority_widget.dart +++ b/lib/app/modules/detailRoute/views/priority_widget.dart @@ -21,11 +21,16 @@ class PriorityWidget extends StatelessWidget { @override Widget build(BuildContext context) { - TaskwarriorColorTheme tColors = Theme.of(context).extension()!; + TaskwarriorColorTheme tColors = + Theme.of(context).extension()!; final Color? textColor = isEditable ? tColors.primaryTextColor : tColors.primaryDisabledTextColor; + // Normalize value: null → X + final String priority = + (value == null || value == '') ? 'X' : value.toString(); + return Card( key: globalKey, color: tColors.secondaryBackgroundColor, @@ -48,7 +53,7 @@ class PriorityWidget extends StatelessWidget { ), ), TextSpan( - text: value ?? "not selected", + text: priority, // Always show X / H / M / L style: GoogleFonts.poppins( fontSize: TaskWarriorFonts.fontSizeMedium, color: textColor, @@ -60,18 +65,24 @@ class PriorityWidget extends StatelessWidget { ], ), ), - onTap: () { - switch (value) { - case 'H': - return callback('M'); - case 'M': - return callback('L'); - case 'L': - return callback(null); - default: - return callback('H'); - } - }, + onTap: isEditable + ? () { + switch (priority) { + case 'X': + callback('H'); + break; + case 'H': + callback('M'); + break; + case 'M': + callback('L'); + break; + case 'L': + callback('X'); + break; + } + } + : null, ), ); }