diff --git a/lib/app/modules/detailRoute/controllers/detail_route_controller.dart b/lib/app/modules/detailRoute/controllers/detail_route_controller.dart index 3bc12109..85c3712c 100644 --- a/lib/app/modules/detailRoute/controllers/detail_route_controller.dart +++ b/lib/app/modules/detailRoute/controllers/detail_route_controller.dart @@ -15,6 +15,7 @@ class DetailRouteController extends GetxController { late String uuid; late Modify modify; var onEdit = false.obs; + var isReadOnly = false.obs; @override void onInit() { @@ -29,12 +30,26 @@ class DetailRouteController extends GetxController { uuid: uuid, ); initValues(); + + // Check if task is completed or deleted and set read-only state + isReadOnly.value = (modify.draft.status == 'completed' || + modify.draft.status == 'deleted'); } void setAttribute(String name, dynamic newValue) { + if (isReadOnly.value && name != 'status') { + return; + } + modify.set(name, newValue); onEdit.value = true; - if(name == 'start'){ + + // If status is being changed, update read-only state + if (name == 'status') { + isReadOnly.value = (newValue == 'completed' || newValue == 'deleted'); + } + + if (name == 'start') { debugPrint('Start Value Changed to $newValue'); startValue.value = newValue; } diff --git a/lib/app/modules/detailRoute/views/dateTimePicker.dart b/lib/app/modules/detailRoute/views/dateTimePicker.dart index fe28aa24..29f135cd 100644 --- a/lib/app/modules/detailRoute/views/dateTimePicker.dart +++ b/lib/app/modules/detailRoute/views/dateTimePicker.dart @@ -15,6 +15,7 @@ class DateTimeWidget extends StatelessWidget { required this.value, required this.callback, required this.globalKey, + this.isEditable = true, }); final String name; @@ -22,15 +23,20 @@ class DateTimeWidget extends StatelessWidget { final dynamic value; final void Function(dynamic) callback; final GlobalKey globalKey; + final bool isEditable; @override Widget build(BuildContext context) { - TaskwarriorColorTheme tColors = Theme.of(context).extension<TaskwarriorColorTheme>()!; + TaskwarriorColorTheme tColors = + Theme.of(context).extension<TaskwarriorColorTheme>()!; return Card( key: globalKey, color: tColors.secondaryBackgroundColor, child: ListTile( - textColor: tColors.primaryTextColor, + enabled: isEditable, + textColor: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, title: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -51,7 +57,9 @@ class DateTimeWidget extends StatelessWidget { fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.bold, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), TextSpan( @@ -65,7 +73,9 @@ class DateTimeWidget extends StatelessWidget { style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), ], @@ -176,7 +186,6 @@ class DateTimeWidget extends StatelessWidget { } } }, - onLongPress: () => callback(null), ), ); @@ -188,20 +197,26 @@ class StartWidget extends StatelessWidget { required this.name, required this.value, required this.callback, + this.isEditable = true, super.key, }); final String name; final dynamic value; + final bool isEditable; final void Function(dynamic) callback; @override Widget build(BuildContext context) { - TaskwarriorColorTheme tColors = Theme.of(context).extension<TaskwarriorColorTheme>()!; + TaskwarriorColorTheme tColors = + Theme.of(context).extension<TaskwarriorColorTheme>()!; return Card( color: tColors.secondaryBackgroundColor, child: ListTile( - textColor: tColors.secondaryBackgroundColor, + enabled: isEditable, + textColor: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, title: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -222,7 +237,9 @@ class StartWidget extends StatelessWidget { fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.bold, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), TextSpan( @@ -236,7 +253,9 @@ class StartWidget extends StatelessWidget { style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), ], diff --git a/lib/app/modules/detailRoute/views/description_widget.dart b/lib/app/modules/detailRoute/views/description_widget.dart index a6421995..4bf3fd82 100644 --- a/lib/app/modules/detailRoute/views/description_widget.dart +++ b/lib/app/modules/detailRoute/views/description_widget.dart @@ -8,15 +8,18 @@ import 'package:taskwarrior/app/utils/gen/fonts.gen.dart'; import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; class DescriptionWidget extends StatelessWidget { - const DescriptionWidget( - {required this.name, - required this.value, - required this.callback, - super.key}); + const DescriptionWidget({ + required this.name, + required this.value, + required this.callback, + this.isEditable = true, + super.key, + }); final String name; final dynamic value; final void Function(dynamic) callback; + final bool isEditable; @override Widget build(BuildContext context) { @@ -25,7 +28,10 @@ class DescriptionWidget extends StatelessWidget { return Card( color: tColors.secondaryBackgroundColor, child: ListTile( - textColor: tColors.primaryTextColor, + enabled: isEditable, + textColor: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, title: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -46,7 +52,9 @@ class DescriptionWidget extends StatelessWidget { fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.bold, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), TextSpan( @@ -60,7 +68,9 @@ class DescriptionWidget extends StatelessWidget { style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), ], @@ -94,7 +104,6 @@ class DescriptionWidget extends StatelessWidget { actions: [ TextButton( onPressed: () { - // Navigator.of(context).pop(); Get.back(); }, child: Text( @@ -108,7 +117,6 @@ class DescriptionWidget extends StatelessWidget { onPressed: () { try { callback(controller.text); - // Navigator.of(context).pop(); Get.back(); } on FormatException catch (e, trace) { logError(e, trace); @@ -131,15 +139,18 @@ class DescriptionWidget extends StatelessWidget { } class ProjectWidget extends StatelessWidget { - const ProjectWidget( - {required this.name, - required this.value, - required this.callback, - super.key}); + const ProjectWidget({ + required this.name, + required this.value, + required this.callback, + this.isEditable = true, + super.key, + }); final String name; final dynamic value; final void Function(dynamic) callback; + final bool isEditable; @override Widget build(BuildContext context) { @@ -148,7 +159,10 @@ class ProjectWidget extends StatelessWidget { return Card( color: tColors.secondaryBackgroundColor, child: ListTile( - textColor: tColors.primaryTextColor, + enabled: isEditable, + textColor: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, title: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -169,7 +183,9 @@ class ProjectWidget extends StatelessWidget { fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.bold, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), TextSpan( @@ -183,7 +199,9 @@ class ProjectWidget extends StatelessWidget { style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor, ), ), ], @@ -217,7 +235,6 @@ class ProjectWidget extends StatelessWidget { actions: [ TextButton( onPressed: () { - // Navigator.of(context).pop(); Get.back(); }, child: Text( @@ -232,7 +249,6 @@ class ProjectWidget extends StatelessWidget { try { callback( (controller.text == '') ? null : controller.text); - // Navigator.of(context).pop(); Get.back(); } on FormatException catch (e, trace) { logError(e, trace); diff --git a/lib/app/modules/detailRoute/views/detail_route_view.dart b/lib/app/modules/detailRoute/views/detail_route_view.dart index bc835b30..7902a6ee 100644 --- a/lib/app/modules/detailRoute/views/detail_route_view.dart +++ b/lib/app/modules/detailRoute/views/detail_route_view.dart @@ -230,12 +230,19 @@ class AttributeWidget extends StatelessWidget { : ((value is BuiltList) ? (value).toBuilder() : value); TaskwarriorColorTheme tColors = Theme.of(context).extension<TaskwarriorColorTheme>()!; + // Get the controller to check if the task is read-only + final DetailRouteController controller = Get.find<DetailRouteController>(); + + // Always allow status to be edited, but respect read-only for other attributes + final bool isEditable = !controller.isReadOnly.value || name == 'status'; + switch (name) { case 'description': return DescriptionWidget( name: name, value: localValue, callback: callback, + isEditable: isEditable, ); case 'status': return StatusWidget( @@ -248,6 +255,7 @@ class AttributeWidget extends StatelessWidget { name: name, value: localValue, callback: callback, + isEditable: isEditable, ); case 'due': return DateTimeWidget( @@ -255,6 +263,7 @@ class AttributeWidget extends StatelessWidget { value: localValue, callback: callback, globalKey: dueKey, + isEditable: isEditable, ); case 'wait': return DateTimeWidget( @@ -262,6 +271,7 @@ class AttributeWidget extends StatelessWidget { value: localValue, callback: callback, globalKey: waitKey, + isEditable: isEditable, ); case 'until': return DateTimeWidget( @@ -269,6 +279,7 @@ class AttributeWidget extends StatelessWidget { value: localValue, callback: callback, globalKey: untilKey, + isEditable: isEditable, ); case 'priority': return PriorityWidget( @@ -276,20 +287,27 @@ class AttributeWidget extends StatelessWidget { value: localValue, callback: callback, globalKey: priorityKey, + isEditable: isEditable, ); case 'project': return ProjectWidget( name: name, value: localValue, callback: callback, + isEditable: isEditable, ); case 'tags': return TagsWidget( name: name, value: localValue, callback: callback, + isEditable: isEditable, ); default: + final Color? textColor = (isEditable && !['entry', 'modified', 'urgency'].contains(name)) + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor; + return Card( color: tColors.secondaryBackgroundColor, child: ListTile( @@ -304,7 +322,7 @@ class AttributeWidget extends StatelessWidget { fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.bold, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: textColor, ), ), Text( @@ -312,7 +330,7 @@ class AttributeWidget extends StatelessWidget { style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: textColor, ), ), ], @@ -322,70 +340,4 @@ class AttributeWidget extends StatelessWidget { ); } } -} - -class TagsWidget extends StatelessWidget { - const TagsWidget({ - required this.name, - required this.value, - required this.callback, - super.key, - }); - - final String name; - final dynamic value; - final void Function(dynamic) callback; - @override - Widget build(BuildContext context) { - TaskwarriorColorTheme tColors = - Theme.of(context).extension<TaskwarriorColorTheme>()!; - return Card( - color: tColors.secondaryBackgroundColor, - child: ListTile( - textColor: tColors.primaryTextColor, - title: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: [ - RichText( - text: TextSpan( - children: <TextSpan>[ - TextSpan( - text: '$name:'.padRight(13), - style: TextStyle( - fontFamily: FontFamily.poppins, - fontWeight: FontWeight.bold, - fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, - ) - // style: GoogleFonts.poppins( - // fontWeight: TaskWarriorFonts.bold, - // fontSize: TaskWarriorFonts.fontSizeMedium, - // color: AppSettings.isDarkMode - // ? TaskWarriorColors.white - // : TaskWarriorColors.black, - // ), - ), - TextSpan( - text: - '${(value as ListBuilder?)?.build() ?? 'not selected'}', - style: TextStyle( - color: tColors.primaryTextColor, - ), - ), - ], - ), - ), - ], - ), - ), - onTap: () => Get.to( - TagsRoute( - value: value, - callback: callback, - ), - ), - ), - ); - } -} +} \ No newline at end of file diff --git a/lib/app/modules/detailRoute/views/priority_widget.dart b/lib/app/modules/detailRoute/views/priority_widget.dart index 56438497..9835ff3c 100644 --- a/lib/app/modules/detailRoute/views/priority_widget.dart +++ b/lib/app/modules/detailRoute/views/priority_widget.dart @@ -4,25 +4,33 @@ import 'package:taskwarrior/app/utils/constants/constants.dart'; import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; class PriorityWidget extends StatelessWidget { - const PriorityWidget( - {required this.name, - required this.value, - required this.callback, - required this.globalKey, - super.key}); + const PriorityWidget({ + required this.name, + required this.value, + required this.callback, + required this.globalKey, + this.isEditable = true, + super.key, + }); final String name; final dynamic value; final void Function(dynamic) callback; final GlobalKey globalKey; + final bool isEditable; @override Widget build(BuildContext context) { TaskwarriorColorTheme tColors = Theme.of(context).extension<TaskwarriorColorTheme>()!; + final Color? textColor = isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor; + return Card( key: globalKey, color: tColors.secondaryBackgroundColor, child: ListTile( + enabled: isEditable, textColor: tColors.primaryTextColor, title: SingleChildScrollView( scrollDirection: Axis.horizontal, @@ -36,14 +44,14 @@ class PriorityWidget extends StatelessWidget { style: GoogleFonts.poppins( fontWeight: TaskWarriorFonts.bold, fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: textColor, ), ), TextSpan( text: value ?? "not selected", style: GoogleFonts.poppins( fontSize: TaskWarriorFonts.fontSizeMedium, - color: tColors.primaryTextColor, + color: textColor, ), ), ], diff --git a/lib/app/modules/detailRoute/views/tags_widget.dart b/lib/app/modules/detailRoute/views/tags_widget.dart index d878238e..6fff7c46 100644 --- a/lib/app/modules/detailRoute/views/tags_widget.dart +++ b/lib/app/modules/detailRoute/views/tags_widget.dart @@ -18,38 +18,46 @@ class TagsWidget extends StatelessWidget { required this.name, required this.value, required this.callback, + this.isEditable = true, super.key, }); final String name; final dynamic value; final void Function(dynamic) callback; + final bool isEditable; @override Widget build(BuildContext context) { TaskwarriorColorTheme tColors = Theme.of(context).extension<TaskwarriorColorTheme>()!; + final Color? textColor = isEditable + ? tColors.primaryTextColor + : tColors.primaryDisabledTextColor; + return Card( + color: tColors.primaryBackgroundColor, child: ListTile( + enabled: isEditable, tileColor: tColors.secondaryBackgroundColor, - textColor: tColors.primaryTextColor, + textColor: textColor, title: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ Text( '${'$name:'.padRight(13)}${(value as ListBuilder?)?.build()}', + style: TextStyle( + color: textColor, + ), ), ], ), ), - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => TagsRoute( - value: value, - callback: callback, - ), + onTap: () => Get.to( + TagsRoute( + value: value, + callback: callback, ), ), ), diff --git a/pubspec.lock b/pubspec.lock index 73a98954..a3cb1127 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1342,6 +1342,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.8" + textfield_tags: + dependency: "direct main" + description: + name: textfield_tags + sha256: d1f2204114157a1296bb97c20d7f8c8c7fd036212812afb2e19de7bb34acc55b + url: "https://pub.dev" + source: hosted + version: "3.0.1" time: dependency: transitive description: