From 7686d0f9cf05c7c0fed484c82d52dace08fcb34c Mon Sep 17 00:00:00 2001 From: Rijad Zuzo Date: Sun, 22 Feb 2026 20:50:48 +0100 Subject: [PATCH] Add floating quick-add button to person insights --- docs/progress.md | 4 ++ lib/features/dashboard/dashboard_view.dart | 64 +++++++++++++++++++ .../dashboard_graph_interactions_test.dart | 1 + 3 files changed, 69 insertions(+) diff --git a/docs/progress.md b/docs/progress.md index 60643ed..d140844 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -25,6 +25,10 @@ the expected context add action. - Updated dashboard interaction coverage: - `test/features/dashboard/dashboard_graph_interactions_test.dart` - now asserts `Quick add` is present after opening `Person Insights`. +- Added visible floating `+` button on `Person Insights` for mobile-first + discoverability: + - opens a bottom sheet with the same quick actions as the header menu + - tooltip: `Add to person` ## Latest Milestone (2026-02-18): Duplicate Profile Merge + Share Deep-Link Polish diff --git a/lib/features/dashboard/dashboard_view.dart b/lib/features/dashboard/dashboard_view.dart index 78af9a6..646dc1d 100644 --- a/lib/features/dashboard/dashboard_view.dart +++ b/lib/features/dashboard/dashboard_view.dart @@ -712,9 +712,20 @@ class _PersonInsightsPage extends ConsumerWidget { final AsyncValue signals = ref.watch( signalsControllerProvider, ); + final LocalDataState? localValue = localData.asData?.value; + final PersonProfile? quickAddPerson = localValue == null + ? null + : _findPersonById(localValue.people, personId); return Scaffold( appBar: AppBar(title: const Text('Person Insights')), + floatingActionButton: quickAddPerson == null + ? null + : FloatingActionButton( + tooltip: 'Add to person', + onPressed: () => _openQuickAddSheet(context, ref, quickAddPerson), + child: const Icon(Icons.add_rounded), + ), body: localData.when( data: (LocalDataState data) { final PersonProfile? person = _findPersonById(data.people, personId); @@ -1143,6 +1154,59 @@ class _PersonInsightsPage extends ConsumerWidget { } } + Future _openQuickAddSheet( + BuildContext context, + WidgetRef ref, + PersonProfile person, + ) async { + final _InsightQuickAction? selected = + await showModalBottomSheet<_InsightQuickAction>( + context: context, + showDragHandle: true, + builder: (BuildContext context) { + return SafeArea( + child: ListView( + shrinkWrap: true, + children: [ + ListTile( + leading: const Icon(Icons.auto_awesome_rounded), + title: const Text('Add Capture'), + subtitle: const Text('Log a new moment or interaction'), + onTap: () => + Navigator.of(context).pop(_InsightQuickAction.capture), + ), + ListTile( + leading: const Icon(Icons.note_add_outlined), + title: const Text('Add Note'), + subtitle: const Text('Save a context note for later'), + onTap: () => + Navigator.of(context).pop(_InsightQuickAction.note), + ), + ListTile( + leading: const Icon(Icons.lightbulb_outline_rounded), + title: const Text('Add Idea'), + subtitle: const Text('Gift or event idea'), + onTap: () => + Navigator.of(context).pop(_InsightQuickAction.idea), + ), + ListTile( + leading: const Icon(Icons.notifications_active_outlined), + title: const Text('Add Reminder'), + subtitle: const Text('Schedule a follow-up prompt'), + onTap: () => + Navigator.of(context).pop(_InsightQuickAction.reminder), + ), + ], + ), + ); + }, + ); + if (selected == null || !context.mounted) { + return; + } + await _handleQuickAction(context, ref, person, selected); + } + Future _showQuickTextCaptureDialog( BuildContext context, { required String title, diff --git a/test/features/dashboard/dashboard_graph_interactions_test.dart b/test/features/dashboard/dashboard_graph_interactions_test.dart index f9864af..cc512a6 100644 --- a/test/features/dashboard/dashboard_graph_interactions_test.dart +++ b/test/features/dashboard/dashboard_graph_interactions_test.dart @@ -42,6 +42,7 @@ void main() { expect(find.text('Person Insights'), findsOneWidget); expect(find.byTooltip('Quick add'), findsOneWidget); + expect(find.byTooltip('Add to person'), findsOneWidget); expect(find.text('Promotions & Signals'), findsOneWidget); expect(find.text('Ideas'), findsOneWidget); expect(find.text('Moments'), findsOneWidget);