From 880bb01a8ab7e44ba2cdfa8570205ce90955ed55 Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Thu, 18 Dec 2025 09:32:28 -0300 Subject: [PATCH 1/6] Handle text input state properly --- .../screens/checklist/checklist_screen.dart | 31 +++++++++---- lib/ui/screens/task/task_screen.dart | 45 ++++++++++++++----- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/lib/ui/screens/checklist/checklist_screen.dart b/lib/ui/screens/checklist/checklist_screen.dart index 6f3e895..f459d9b 100644 --- a/lib/ui/screens/checklist/checklist_screen.dart +++ b/lib/ui/screens/checklist/checklist_screen.dart @@ -30,21 +30,29 @@ class ChecklistScreen extends StatelessWidget { } } -class ChecklistScreenScaffold extends StatelessWidget { - final TextEditingController _checklistEditingController = - TextEditingController(); +class ChecklistScreenScaffold extends StatefulWidget { final Function(String) onAddNewChecklist; - final _formKey = GlobalKey(); final FormScreenValidator formScreenValidator; final NavigatorProvider navigatorProvider; - ChecklistScreenScaffold({ + const ChecklistScreenScaffold({ super.key, required this.onAddNewChecklist, required this.formScreenValidator, required this.navigatorProvider, }); + @override + State createState() => + _ChecklistScreenScaffoldState(); +} + +class _ChecklistScreenScaffoldState extends State { + final TextEditingController _checklistEditingController = + TextEditingController(); + + final _formKey = GlobalKey(); + @override Widget build(BuildContext context) { final localizations = AppLocalizations.of(context)!; @@ -59,11 +67,11 @@ class ChecklistScreenScaffold extends StatelessWidget { return; } - await onAddNewChecklist( + await widget.onAddNewChecklist( _checklistEditingController.text, ); if (context.mounted) { - navigatorProvider.onPop(context, true); + widget.navigatorProvider.onPop(context, true); } }, child: const Icon(Icons.save), @@ -74,10 +82,17 @@ class ChecklistScreenScaffold extends StatelessWidget { formKey: _formKey, checklistLabel: localizations.checklist_name, checklistErrorMessage: localizations.checklist_name_required, - formScreenValidator: formScreenValidator, + formScreenValidator: widget.formScreenValidator, checklistEditingController: _checklistEditingController, ), ), ); } + + @override + void dispose() { + _checklistEditingController.dispose(); + + super.dispose(); + } } diff --git a/lib/ui/screens/task/task_screen.dart b/lib/ui/screens/task/task_screen.dart index 2bb9c71..294ce4d 100644 --- a/lib/ui/screens/task/task_screen.dart +++ b/lib/ui/screens/task/task_screen.dart @@ -42,29 +42,43 @@ class TaskScreen extends StatelessWidget { } } -class TaskScreenScaffold extends StatelessWidget { - final TextEditingController _taskEditingController = TextEditingController(); +class TaskScreenScaffold extends StatefulWidget { final Future Function(String) addTaskOrUpdate; final FormScreenValidator formScreenValidator; - final _formKey = GlobalKey(); final NavigatorProvider navigatorProvider; final IconData floatingActionIcon; + final String? taskTitle; - TaskScreenScaffold({ + const TaskScreenScaffold({ super.key, - String? taskTitle, + this.taskTitle, required this.floatingActionIcon, required this.addTaskOrUpdate, required this.formScreenValidator, required this.navigatorProvider, - }) { - _taskEditingController.text = taskTitle ?? ''; + }); + + @override + State createState() => _TaskScreenScaffoldState(); +} + +class _TaskScreenScaffoldState extends State { + late TextEditingController _taskEditingController; + + final _formKey = GlobalKey(); + + @override + void initState() { + super.initState(); + + _taskEditingController = TextEditingController( + text: widget.taskTitle ?? '' + ); } @override Widget build(BuildContext context) { final localizations = AppLocalizations.of(context)!; - return Scaffold( appBar: CustomAppBarWidget( title: localizations.task, @@ -75,14 +89,14 @@ class TaskScreenScaffold extends StatelessWidget { return; } - final result = await addTaskOrUpdate( + final result = await widget.addTaskOrUpdate( _taskEditingController.text, ); if (context.mounted) { - navigatorProvider.onPop(context, result); + widget.navigatorProvider.onPop(context, result); } }, - child: Icon(floatingActionIcon), + child: Icon(widget.floatingActionIcon), ), body: Padding( padding: const EdgeInsets.all(12), @@ -91,9 +105,16 @@ class TaskScreenScaffold extends StatelessWidget { taskLabel: localizations.task, taskErrorMessage: localizations.task_name_required, taskEditingController: _taskEditingController, - formScreenValidator: formScreenValidator, + formScreenValidator: widget.formScreenValidator, ), ), ); } + + @override + void dispose() { + _taskEditingController.dispose(); + + super.dispose(); + } } From 1471025b96c1fb5e71ed1cae2d0afa13c1a1498b Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Fri, 19 Dec 2025 22:47:31 -0300 Subject: [PATCH 2/6] Remove StartupViewmodel and refactor StartupScreen to Stateful widget --- lib/ui/screens/startup/startup_screen.dart | 41 +++++++++++-------- lib/ui/screens/startup/startup_viewmodel.dart | 15 ------- 2 files changed, 25 insertions(+), 31 deletions(-) delete mode 100644 lib/ui/screens/startup/startup_viewmodel.dart diff --git a/lib/ui/screens/startup/startup_screen.dart b/lib/ui/screens/startup/startup_screen.dart index 27d2231..121a426 100644 --- a/lib/ui/screens/startup/startup_screen.dart +++ b/lib/ui/screens/startup/startup_screen.dart @@ -1,23 +1,35 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:todoapp/ui/screens/startup/startup_viewmodel.dart'; import 'package:todoapp/ui/todo_app_router_config.gr.dart'; +import 'package:todoapp/util/di/dependency_startup_launcher.dart'; @RoutePage() -class StartupScreen extends StatelessWidget { +class StartupScreen extends StatefulWidget { const StartupScreen({super.key}); + @override + State createState() => _StartupScreenState(); +} + +class _StartupScreenState extends State { + StackRouter? _stackRouter; + + @override + void initState() { + super.initState(); + _loadDependencies(); + } + + Future _loadDependencies() async { + await GetItStartupHandlerWrapper.init(); + _stackRouter?.replace(const ChecklistsRoute()); + } + @override Widget build(BuildContext context) { - final viewModel = StartupViewmodel(); - return BlocProvider( - create: (_) => viewModel, - child: BlocBuilder( - builder: (context, uiState) => StartupContainer( - isLoading: uiState, - ), - ), + _stackRouter = AutoRouter.of(context); + return const StartupContainer( + isLoading: true, ); } } @@ -25,16 +37,13 @@ class StartupScreen extends StatelessWidget { class StartupContainer extends StatelessWidget { final bool isLoading; - const StartupContainer({super.key, + const StartupContainer({ + super.key, required this.isLoading, }); @override Widget build(BuildContext context) { - if (isLoading == false) { - AutoRouter.of(context).replace(const ChecklistsRoute()); - } - return Container( color: Theme.of(context).colorScheme.primaryContainer, child: Center( diff --git a/lib/ui/screens/startup/startup_viewmodel.dart b/lib/ui/screens/startup/startup_viewmodel.dart deleted file mode 100644 index de08d30..0000000 --- a/lib/ui/screens/startup/startup_viewmodel.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:todoapp/util/di/dependency_startup_launcher.dart'; - -class StartupViewmodel extends Cubit { - - StartupViewmodel() : super(true) { - _loadDependencies(); - } - - Future _loadDependencies() async { - await GetItStartupHandlerWrapper.init(); - await Future.delayed(const Duration(milliseconds: 500)); - emit(false); - } -} From 30530d89ad4e054941346fd5e89e2ac8416522b9 Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Fri, 19 Dec 2025 22:51:48 -0300 Subject: [PATCH 3/6] nit --- lib/domain/tasks_comparator_use_case.dart | 6 ++++-- lib/domain/tasks_sorter_use_case.dart | 1 - .../checklist/fabmenu/checklist_fabmenu_item.dart | 13 +++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/domain/tasks_comparator_use_case.dart b/lib/domain/tasks_comparator_use_case.dart index 075a3a3..acc718a 100644 --- a/lib/domain/tasks_comparator_use_case.dart +++ b/lib/domain/tasks_comparator_use_case.dart @@ -8,8 +8,10 @@ abstract class TasksComparatorUseCase { @Injectable(as: TasksComparatorUseCase) class TasksComparatorUseCaseImpl extends TasksComparatorUseCase { @override - bool areThemEqual( - {required List oldList, required List newList}) { + bool areThemEqual({ + required List oldList, + required List newList, + }) { if (oldList.length == newList.length) { if (oldList.isEmpty && newList.isEmpty) { return true; diff --git a/lib/domain/tasks_sorter_use_case.dart b/lib/domain/tasks_sorter_use_case.dart index 522f4e3..a3c111c 100644 --- a/lib/domain/tasks_sorter_use_case.dart +++ b/lib/domain/tasks_sorter_use_case.dart @@ -23,5 +23,4 @@ class TasksSorterUseCaseImpl implements TasksSorterUseCase { return 0; } } - } \ No newline at end of file diff --git a/lib/ui/components/widgets/checklist/fabmenu/checklist_fabmenu_item.dart b/lib/ui/components/widgets/checklist/fabmenu/checklist_fabmenu_item.dart index 06ec999..2cde2d0 100644 --- a/lib/ui/components/widgets/checklist/fabmenu/checklist_fabmenu_item.dart +++ b/lib/ui/components/widgets/checklist/fabmenu/checklist_fabmenu_item.dart @@ -6,12 +6,13 @@ class ChecklistFabMenuItem extends StatelessWidget { final IconData icon; final Function() onPressed; - const ChecklistFabMenuItem( - {super.key, - required this.label, - required this.onPressed, - required this.icon, - required this.heroTag}); + const ChecklistFabMenuItem({ + super.key, + required this.label, + required this.onPressed, + required this.icon, + required this.heroTag, + }); @override Widget build(BuildContext context) { From f1e650de40cd2b2987166e0dd24a5efde0bd515e Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Sat, 20 Dec 2025 09:57:58 -0300 Subject: [PATCH 4/6] Refactor CardWrapperWidget to accept elevation and shapeBorder parameters; update ChecklistItemWidget and TaskCellWidget to utilize new properties. --- .../widgets/card_wrapper_widget.dart | 26 ++++++++++++------- .../checklist/checklist_item_widget.dart | 12 +++++++++ .../widgets/task/task_cell_widget.dart | 2 ++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/ui/components/widgets/card_wrapper_widget.dart b/lib/ui/components/widgets/card_wrapper_widget.dart index b1d81d1..d46598e 100644 --- a/lib/ui/components/widgets/card_wrapper_widget.dart +++ b/lib/ui/components/widgets/card_wrapper_widget.dart @@ -4,20 +4,28 @@ class CardWrapperWidget extends StatelessWidget { final Color backgroundColor; final Function()? onTap; final Widget child; + final ShapeBorder? shapeBorder; + final double? elevation; - const CardWrapperWidget( - {super.key, - required this.child, - required this.onTap, - required this.backgroundColor}); + static const commonShapeBorder = RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ); + static const commonElevation = 2.0; + + const CardWrapperWidget({ + super.key, + required this.child, + required this.onTap, + required this.backgroundColor, + this.elevation, + this.shapeBorder, + }); @override Widget build(BuildContext context) { return Card( - elevation: 2, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(12)), - ), + elevation: elevation, + shape: shapeBorder, color: backgroundColor, clipBehavior: Clip.hardEdge, child: InkWell( diff --git a/lib/ui/components/widgets/checklist/checklist_item_widget.dart b/lib/ui/components/widgets/checklist/checklist_item_widget.dart index 04caadf..7513d07 100644 --- a/lib/ui/components/widgets/checklist/checklist_item_widget.dart +++ b/lib/ui/components/widgets/checklist/checklist_item_widget.dart @@ -39,14 +39,26 @@ class ChecklistItemWidget extends StatelessWidget { @override Widget build(BuildContext context) { Color backgroundColor = Theme.of(context).colorScheme.surfaceBright; + ShapeBorder shapeBorder = CardWrapperWidget.commonShapeBorder; + double? elevation = CardWrapperWidget.commonElevation; if (isSelected == true) { backgroundColor = Theme.of(context).colorScheme.tertiaryContainer; + shapeBorder = const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12), + topRight: Radius.circular(12), + ), + ); + elevation = null; } return CardWrapperWidget( onTap: () => onSelectChecklist(checklist), backgroundColor: backgroundColor, + elevation: elevation, + shapeBorder: shapeBorder, child: _internalContent(context, checklist), ); } diff --git a/lib/ui/components/widgets/task/task_cell_widget.dart b/lib/ui/components/widgets/task/task_cell_widget.dart index 9a0d4b5..4f8fad7 100644 --- a/lib/ui/components/widgets/task/task_cell_widget.dart +++ b/lib/ui/components/widgets/task/task_cell_widget.dart @@ -22,6 +22,8 @@ class TaskCellWidget extends StatelessWidget { @override Widget build(BuildContext context) { return CardWrapperWidget( + elevation: CardWrapperWidget.commonElevation, + shapeBorder: CardWrapperWidget.commonShapeBorder, onTap: null, backgroundColor: Theme.of(context).colorScheme.surfaceBright, child: ListTile( From afa420a245415695e65b4a3e3c1229b2413df4b2 Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Sat, 20 Dec 2025 10:13:33 -0300 Subject: [PATCH 5/6] Refactor CardWrapperWidget to manage background color and elevation based on selection state; update ChecklistItemWidget and TaskCellWidget to utilize new logic. --- .../widgets/card_wrapper_widget.dart | 45 ++++++++++++------- .../checklist/checklist_item_widget.dart | 20 +-------- .../widgets/task/task_cell_widget.dart | 3 -- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/lib/ui/components/widgets/card_wrapper_widget.dart b/lib/ui/components/widgets/card_wrapper_widget.dart index d46598e..8fdef3e 100644 --- a/lib/ui/components/widgets/card_wrapper_widget.dart +++ b/lib/ui/components/widgets/card_wrapper_widget.dart @@ -1,37 +1,50 @@ import 'package:flutter/material.dart'; class CardWrapperWidget extends StatelessWidget { - final Color backgroundColor; final Function()? onTap; final Widget child; final ShapeBorder? shapeBorder; final double? elevation; - - static const commonShapeBorder = RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(12)), - ); - static const commonElevation = 2.0; + final bool? isSelected; const CardWrapperWidget({ super.key, required this.child, required this.onTap, - required this.backgroundColor, this.elevation, this.shapeBorder, + this.isSelected, }); @override Widget build(BuildContext context) { - return Card( - elevation: elevation, - shape: shapeBorder, - color: backgroundColor, - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: onTap, + if (isSelected == true) { + return Card( + elevation: 0, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12), + bottomLeft: Radius.circular(12), + topRight: Radius.circular(12), + ), + ), + color: Theme.of(context).colorScheme.tertiaryContainer, + clipBehavior: Clip.hardEdge, child: child, - ), - ); + ); + } else { + return Card( + elevation: 2, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + clipBehavior: Clip.hardEdge, + color: Theme.of(context).colorScheme.surfaceBright, + child: InkWell( + onTap: onTap, + child: child, + ), + ); + } } } diff --git a/lib/ui/components/widgets/checklist/checklist_item_widget.dart b/lib/ui/components/widgets/checklist/checklist_item_widget.dart index 7513d07..a9dadca 100644 --- a/lib/ui/components/widgets/checklist/checklist_item_widget.dart +++ b/lib/ui/components/widgets/checklist/checklist_item_widget.dart @@ -38,27 +38,9 @@ class ChecklistItemWidget extends StatelessWidget { @override Widget build(BuildContext context) { - Color backgroundColor = Theme.of(context).colorScheme.surfaceBright; - ShapeBorder shapeBorder = CardWrapperWidget.commonShapeBorder; - double? elevation = CardWrapperWidget.commonElevation; - - if (isSelected == true) { - backgroundColor = Theme.of(context).colorScheme.tertiaryContainer; - shapeBorder = const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(12), - bottomLeft: Radius.circular(12), - topRight: Radius.circular(12), - ), - ); - elevation = null; - } - return CardWrapperWidget( + isSelected: isSelected, onTap: () => onSelectChecklist(checklist), - backgroundColor: backgroundColor, - elevation: elevation, - shapeBorder: shapeBorder, child: _internalContent(context, checklist), ); } diff --git a/lib/ui/components/widgets/task/task_cell_widget.dart b/lib/ui/components/widgets/task/task_cell_widget.dart index 4f8fad7..d612910 100644 --- a/lib/ui/components/widgets/task/task_cell_widget.dart +++ b/lib/ui/components/widgets/task/task_cell_widget.dart @@ -22,10 +22,7 @@ class TaskCellWidget extends StatelessWidget { @override Widget build(BuildContext context) { return CardWrapperWidget( - elevation: CardWrapperWidget.commonElevation, - shapeBorder: CardWrapperWidget.commonShapeBorder, onTap: null, - backgroundColor: Theme.of(context).colorScheme.surfaceBright, child: ListTile( leading: IconButton( onPressed: () => {onRemoveTask(task)}, From cd165345e9ba5054ee89de5b5369ff1340afbe2a Mon Sep 17 00:00:00 2001 From: Gabriel Moro Date: Sat, 20 Dec 2025 10:24:49 -0300 Subject: [PATCH 6/6] Bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index d0aa462..ac2b3b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+15 +version: 1.0.0+16 environment: sdk: ^3.5.0