From 39a6a56352d209cc79f2a68448600f297f65c4b8 Mon Sep 17 00:00:00 2001 From: Matthias Nehlsen Date: Mon, 18 Nov 2024 01:49:57 +0100 Subject: [PATCH] feat: checklist completion progress bar --- .../tasks/state/checklist_controller.dart | 24 +++ .../tasks/state/checklist_controller.g.dart | 151 ++++++++++++++++++ lib/features/tasks/ui/checklist_widget.dart | 10 +- pubspec.yaml | 2 +- 4 files changed, 184 insertions(+), 3 deletions(-) diff --git a/lib/features/tasks/state/checklist_controller.dart b/lib/features/tasks/state/checklist_controller.dart index 809cef0ce..eee38c997 100644 --- a/lib/features/tasks/state/checklist_controller.dart +++ b/lib/features/tasks/state/checklist_controller.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:lotti/classes/journal_entities.dart'; import 'package:lotti/database/database.dart'; +import 'package:lotti/features/tasks/state/checklist_item_controller.dart'; import 'package:lotti/get_it.dart'; import 'package:lotti/logic/persistence_logic.dart'; import 'package:lotti/services/db_notification.dart'; @@ -102,3 +103,26 @@ class ChecklistController extends _$ChecklistController { } } } + +@riverpod +class ChecklistCompletionController extends _$ChecklistCompletionController { + ChecklistCompletionController(); + + @override + Future build({required String id}) async { + final checklistData = + ref.watch(checklistControllerProvider(id: id)).value?.data; + + final linkedIds = checklistData?.linkedChecklistItems ?? []; + final total = linkedIds.length; + + final linkedChecklistItems = linkedIds + .map((id) => ref.watch(checklistItemControllerProvider(id: id)).value); + + final completed = linkedChecklistItems + .where((item) => item?.data.isChecked ?? false) + .length; + + return total == 0 ? 0.0 : completed / total; + } +} diff --git a/lib/features/tasks/state/checklist_controller.g.dart b/lib/features/tasks/state/checklist_controller.g.dart index 1c55053e1..9fb3a155e 100644 --- a/lib/features/tasks/state/checklist_controller.g.dart +++ b/lib/features/tasks/state/checklist_controller.g.dart @@ -174,5 +174,156 @@ class _ChecklistControllerProviderElement @override String get id => (origin as ChecklistControllerProvider).id; } + +String _$checklistCompletionControllerHash() => + r'5a77b1e2f4430530570968cae7eeea098ea9aaf7'; + +abstract class _$ChecklistCompletionController + extends BuildlessAutoDisposeAsyncNotifier { + late final String id; + + FutureOr build({ + required String id, + }); +} + +/// See also [ChecklistCompletionController]. +@ProviderFor(ChecklistCompletionController) +const checklistCompletionControllerProvider = + ChecklistCompletionControllerFamily(); + +/// See also [ChecklistCompletionController]. +class ChecklistCompletionControllerFamily extends Family> { + /// See also [ChecklistCompletionController]. + const ChecklistCompletionControllerFamily(); + + /// See also [ChecklistCompletionController]. + ChecklistCompletionControllerProvider call({ + required String id, + }) { + return ChecklistCompletionControllerProvider( + id: id, + ); + } + + @override + ChecklistCompletionControllerProvider getProviderOverride( + covariant ChecklistCompletionControllerProvider provider, + ) { + return call( + id: provider.id, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'checklistCompletionControllerProvider'; +} + +/// See also [ChecklistCompletionController]. +class ChecklistCompletionControllerProvider + extends AutoDisposeAsyncNotifierProviderImpl { + /// See also [ChecklistCompletionController]. + ChecklistCompletionControllerProvider({ + required String id, + }) : this._internal( + () => ChecklistCompletionController()..id = id, + from: checklistCompletionControllerProvider, + name: r'checklistCompletionControllerProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$checklistCompletionControllerHash, + dependencies: ChecklistCompletionControllerFamily._dependencies, + allTransitiveDependencies: + ChecklistCompletionControllerFamily._allTransitiveDependencies, + id: id, + ); + + ChecklistCompletionControllerProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.id, + }) : super.internal(); + + final String id; + + @override + FutureOr runNotifierBuild( + covariant ChecklistCompletionController notifier, + ) { + return notifier.build( + id: id, + ); + } + + @override + Override overrideWith(ChecklistCompletionController Function() create) { + return ProviderOverride( + origin: this, + override: ChecklistCompletionControllerProvider._internal( + () => create()..id = id, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + id: id, + ), + ); + } + + @override + AutoDisposeAsyncNotifierProviderElement + createElement() { + return _ChecklistCompletionControllerProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is ChecklistCompletionControllerProvider && other.id == id; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, id.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin ChecklistCompletionControllerRef + on AutoDisposeAsyncNotifierProviderRef { + /// The parameter `id` of this provider. + String get id; +} + +class _ChecklistCompletionControllerProviderElement + extends AutoDisposeAsyncNotifierProviderElement< + ChecklistCompletionController, + double> with ChecklistCompletionControllerRef { + _ChecklistCompletionControllerProviderElement(super.provider); + + @override + String get id => (origin as ChecklistCompletionControllerProvider).id; +} // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/features/tasks/ui/checklist_widget.dart b/lib/features/tasks/ui/checklist_widget.dart index 4e8a47b39..5afbd7e1d 100644 --- a/lib/features/tasks/ui/checklist_widget.dart +++ b/lib/features/tasks/ui/checklist_widget.dart @@ -11,6 +11,7 @@ class ChecklistWidget extends StatefulWidget { required this.itemIds, required this.onTitleSave, required this.onCreateChecklistItem, + this.completionRate = 0.0, super.key, }); @@ -18,6 +19,7 @@ class ChecklistWidget extends StatefulWidget { final List itemIds; final StringCallback onTitleSave; final StringCallback onCreateChecklistItem; + final double completionRate; @override State createState() => _ChecklistWidgetState(); @@ -69,8 +71,8 @@ class _ChecklistWidgetState extends State { crossFadeState: _isEditing ? CrossFadeState.showFirst : CrossFadeState.showSecond, ), - subtitle: const LinearProgressIndicator( - value: 0.87, + subtitle: LinearProgressIndicator( + value: widget.completionRate, semanticsLabel: 'Checklist progress', ), children: [ @@ -107,6 +109,9 @@ class ChecklistWrapper extends ConsumerWidget { final notifier = ref.read(provider.notifier); final checklist = ref.watch(provider).value; + final completionRate = + ref.watch(checklistCompletionControllerProvider(id: entryId)).value; + if (checklist == null) { return const SizedBox.shrink(); } @@ -116,6 +121,7 @@ class ChecklistWrapper extends ConsumerWidget { itemIds: checklist.data.linkedChecklistItems, onTitleSave: notifier.updateTitle, onCreateChecklistItem: notifier.createChecklistItem, + completionRate: completionRate ?? 0.0, ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 59385670f..f87beed19 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: lotti description: Achieve your goals and keep your data private with Lotti. publish_to: 'none' -version: 0.9.531+2731 +version: 0.9.531+2732 msix_config: display_name: LottiApp