From fb741305ac1710fee5872947d293a981a33dd05c Mon Sep 17 00:00:00 2001 From: Wayne Duran Date: Fri, 10 Jun 2022 14:11:27 +0800 Subject: [PATCH] feat: can now add new activities --- README.md | 4 +- lib/elements/activity_dialog.dart | 55 ++++++++++++++++ ..._activity.dart => activity_list_tile.dart} | 4 +- ....dart => choose_and_order_activities.dart} | 18 +++--- lib/elements/editable_activity_tile.dart | 40 ++++++++++++ lib/models/activity.dart | 4 ++ lib/models/activity_repository.dart | 5 ++ lib/settings_page.dart | 62 ++++++++++++------- lib/tools/reorder.dart | 5 ++ test/tools/reorder_test.dart | 21 +++++++ 10 files changed, 185 insertions(+), 33 deletions(-) create mode 100644 lib/elements/activity_dialog.dart rename lib/elements/{editable_activity.dart => activity_list_tile.dart} (78%) rename lib/elements/{edit_activities.dart => choose_and_order_activities.dart} (86%) create mode 100644 lib/elements/editable_activity_tile.dart create mode 100644 lib/tools/reorder.dart create mode 100644 test/tools/reorder_test.dart diff --git a/README.md b/README.md index d741155..d7666f0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # Aralan -Homeschool tools +Tools to keep track of daily homeschool activities. + + diff --git a/lib/elements/activity_dialog.dart b/lib/elements/activity_dialog.dart new file mode 100644 index 0000000..32192b4 --- /dev/null +++ b/lib/elements/activity_dialog.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +import '../models/activity.dart'; + +class ActivityDialog extends StatefulWidget { + final Activity activity; + const ActivityDialog({Key? key, required this.activity}) : super(key: key); + + static Future open(BuildContext context, Activity activity) { + return showDialog( + context: context, + builder: (context) => ActivityDialog(activity: activity), + ); + } + + @override + State createState() => _ActivityDialogState(); +} + +class _ActivityDialogState extends State { + late Activity activity; + + @override + initState() { + super.initState(); + activity = widget.activity; + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Edit Activity'), + content: TextFormField( + autofocus: true, + decoration: const InputDecoration(hintText: 'Enter activity name'), + initialValue: activity.name, + onChanged: (str) { + setState(() { + activity = activity.update(name: str); + }); + }, + ), + actions: [ + TextButton( + onPressed: () => submit(context), + child: const Text('SAVE'), + ), + ], + ); + } + + void submit(BuildContext context) { + Navigator.of(context).pop(activity); + } +} diff --git a/lib/elements/editable_activity.dart b/lib/elements/activity_list_tile.dart similarity index 78% rename from lib/elements/editable_activity.dart rename to lib/elements/activity_list_tile.dart index aa1d366..9fa850c 100644 --- a/lib/elements/editable_activity.dart +++ b/lib/elements/activity_list_tile.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import '../models/activity.dart'; -class EditableActivity extends StatelessWidget { +class ActivityListTile extends StatelessWidget { final Activity activity; - const EditableActivity({Key? key, required this.activity}) : super(key: key); + const ActivityListTile({Key? key, required this.activity}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/elements/edit_activities.dart b/lib/elements/choose_and_order_activities.dart similarity index 86% rename from lib/elements/edit_activities.dart rename to lib/elements/choose_and_order_activities.dart index be70154..4355148 100644 --- a/lib/elements/edit_activities.dart +++ b/lib/elements/choose_and_order_activities.dart @@ -1,19 +1,20 @@ import 'package:aralan/elements/toggle_activity.dart'; +import 'package:aralan/tools/reorder.dart'; import 'package:flutter/material.dart'; import '../models/activity.dart'; -import 'editable_activity.dart'; +import 'activity_list_tile.dart'; import 'h3.dart'; import 'list_container.dart'; typedef OnChooseActivities = Function(List activity); -class EditActivities extends StatefulWidget { +class ChooseAndOrderActivities extends StatefulWidget { final List list; final OnChooseActivities onChoose; final List available; final String? title; - const EditActivities({ + const ChooseAndOrderActivities({ Key? key, required this.list, required this.onChoose, @@ -22,10 +23,11 @@ class EditActivities extends StatefulWidget { }) : super(key: key); @override - State createState() => _EditActivitiesState(); + State createState() => + _ChooseAndOrderActivitiesState(); } -class _EditActivitiesState extends State { +class _ChooseAndOrderActivitiesState extends State { Set _selectedActivities = {}; @override @@ -89,14 +91,12 @@ class _EditActivitiesState extends State { onReorder: (a, b) { setState(() { final tempList = _selectedActivities.toList(); - final removed = tempList.removeAt(a); - tempList.insert(b, removed); - _selectedActivities = Set.from(tempList); + _selectedActivities = Set.from(reorder(tempList, a, b)); widget.onChoose(_chosenActivities()); }); }, builder: (activity, _) { - return EditableActivity( + return ActivityListTile( key: Key(activity.id), activity: activity, ); diff --git a/lib/elements/editable_activity_tile.dart b/lib/elements/editable_activity_tile.dart new file mode 100644 index 0000000..30cd823 --- /dev/null +++ b/lib/elements/editable_activity_tile.dart @@ -0,0 +1,40 @@ +import 'package:aralan/elements/activity_dialog.dart'; +import 'package:flutter/material.dart'; + +import '../models/activity.dart'; + +typedef OnChangeActivity = void Function(Activity activity); + +class EditableActivityTile extends StatelessWidget { + final Activity activity; + final OnChangeActivity onChange; + + const EditableActivityTile({ + Key? key, + required this.activity, + required this.onChange, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return ListTile( + dense: true, + title: Text( + activity.name, + style: theme.textTheme.headline4?.copyWith( + fontWeight: FontWeight.normal, + ), + ), + leading: IconButton( + icon: const Icon(Icons.edit), + onPressed: () async { + final updated = await ActivityDialog.open(context, activity); + if (updated != null) { + onChange(updated); + } + }, + ), + ); + } +} diff --git a/lib/models/activity.dart b/lib/models/activity.dart index a269f46..da493cd 100644 --- a/lib/models/activity.dart +++ b/lib/models/activity.dart @@ -21,6 +21,10 @@ class Activity extends ActivityLike { 'name': name, 'id': id, }; + + Activity update({required name}) { + return Activity(name: name, id: id); + } } class CheckableActivity extends ActivityLike { diff --git a/lib/models/activity_repository.dart b/lib/models/activity_repository.dart index 51716e0..999f6b3 100644 --- a/lib/models/activity_repository.dart +++ b/lib/models/activity_repository.dart @@ -77,6 +77,11 @@ class ActivityRepository extends ChangeNotifier { _updateStore(); } + update(Activity activity) { + _activitiesCache[activity.id] = activity; + _updateStore(); + } + List forWeekday(int weekday) { final ids = _prefs.getStringList(_weekDayKey(weekday)); if (ids != null) { diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 5ccd1eb..108b7fc 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -1,5 +1,6 @@ -import 'package:aralan/elements/edit_activities.dart'; -import 'package:aralan/elements/editable_activity.dart'; +import 'package:aralan/elements/activity_dialog.dart'; +import 'package:aralan/elements/choose_and_order_activities.dart'; +import 'package:aralan/elements/editable_activity_tile.dart'; import 'package:aralan/elements/navigation_button.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -21,6 +22,24 @@ class SettingsPage extends StatelessWidget { final allActivities = repo.all(); final now = DateTime.now(); + onChooseActivitiesToday(activities) { + repo.updateActivitiesToday( + ActivitiesToday.fromPlainActivities( + now, + activities, + ), + ); + } + + onChooseDailyActivities(int weekday) { + return (activities) { + repo.updateForWeekday( + weekday, + activities, + ); + }; + } + return Scaffold( body: SingleChildScrollView( child: Stack( @@ -49,11 +68,24 @@ class SettingsPage extends StatelessWidget { ListContainer( list: allActivities, builder: (activity, context) { - return EditableActivity( - activity: activity, - ); + return EditableActivityTile( + activity: activity, + onChange: (activity) { + // debugPrint('Edited: ${activity.name}'); + repo.update(activity); + }); }, ), + TextButton( + onPressed: () async { + final newActivity = await ActivityDialog.open( + context, Activity(name: '')); + if (newActivity is Activity) { + repo.add(newActivity); + } + }, + child: const Text('Add an Activity'), + ), ], ), ), @@ -61,30 +93,18 @@ class SettingsPage extends StatelessWidget { child: Column( children: [ const H2('Day Activities'), - EditActivities( + ChooseAndOrderActivities( title: 'Activities Today', list: repo.activitiesToday(now).plainActivities(), - onChoose: (activities) { - repo.updateActivitiesToday( - ActivitiesToday.fromPlainActivities( - now, - activities, - ), - ); - }, + onChoose: onChooseActivitiesToday, available: allActivities, ), ...(weekdays.keys.map((weekday) { - return EditActivities( + return ChooseAndOrderActivities( title: weekdays[weekday].toString(), list: repo.forWeekday(weekday), available: allActivities, - onChoose: (activities) { - repo.updateForWeekday( - weekday, - activities, - ); - }, + onChoose: onChooseDailyActivities(weekday), ); })), ], diff --git a/lib/tools/reorder.dart b/lib/tools/reorder.dart new file mode 100644 index 0000000..542a8a6 --- /dev/null +++ b/lib/tools/reorder.dart @@ -0,0 +1,5 @@ +List reorder(List list, int indexBefore, int indexAfter) { + final removed = list.removeAt(indexBefore); + list.insert(indexAfter, removed); + return list; +} diff --git a/test/tools/reorder_test.dart b/test/tools/reorder_test.dart new file mode 100644 index 0000000..920f8fc --- /dev/null +++ b/test/tools/reorder_test.dart @@ -0,0 +1,21 @@ +import 'package:aralan/tools/reorder.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('reorder()', () { + test('It should move 2nd element to first', () { + final list = [1, 2, 3, 4]; + expect(reorder(list, 1, 0), [2, 1, 3, 4]); + }); + + test('It should move 3rd element to last', () { + final list = [1, 2, 3, 4]; + expect(reorder(list, 2, 3), [1, 2, 4, 3]); + }); + + test('It should move last element to first', () { + final list = [1, 2, 3, 4]; + expect(reorder(list, 3, 0), [4, 1, 2, 3]); + }); + }); +}