Add floating quick-add button to person insights
This commit is contained in:
@@ -25,6 +25,10 @@ the expected context add action.
|
|||||||
- Updated dashboard interaction coverage:
|
- Updated dashboard interaction coverage:
|
||||||
- `test/features/dashboard/dashboard_graph_interactions_test.dart`
|
- `test/features/dashboard/dashboard_graph_interactions_test.dart`
|
||||||
- now asserts `Quick add` is present after opening `Person Insights`.
|
- 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
|
## Latest Milestone (2026-02-18): Duplicate Profile Merge + Share Deep-Link Polish
|
||||||
|
|
||||||
|
|||||||
@@ -712,9 +712,20 @@ class _PersonInsightsPage extends ConsumerWidget {
|
|||||||
final AsyncValue<SignalsFeed> signals = ref.watch(
|
final AsyncValue<SignalsFeed> signals = ref.watch(
|
||||||
signalsControllerProvider,
|
signalsControllerProvider,
|
||||||
);
|
);
|
||||||
|
final LocalDataState? localValue = localData.asData?.value;
|
||||||
|
final PersonProfile? quickAddPerson = localValue == null
|
||||||
|
? null
|
||||||
|
: _findPersonById(localValue.people, personId);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Person Insights')),
|
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(
|
body: localData.when(
|
||||||
data: (LocalDataState data) {
|
data: (LocalDataState data) {
|
||||||
final PersonProfile? person = _findPersonById(data.people, personId);
|
final PersonProfile? person = _findPersonById(data.people, personId);
|
||||||
@@ -1143,6 +1154,59 @@ class _PersonInsightsPage extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _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: <Widget>[
|
||||||
|
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<String?> _showQuickTextCaptureDialog(
|
Future<String?> _showQuickTextCaptureDialog(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required String title,
|
required String title,
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ void main() {
|
|||||||
|
|
||||||
expect(find.text('Person Insights'), findsOneWidget);
|
expect(find.text('Person Insights'), findsOneWidget);
|
||||||
expect(find.byTooltip('Quick add'), findsOneWidget);
|
expect(find.byTooltip('Quick add'), findsOneWidget);
|
||||||
|
expect(find.byTooltip('Add to person'), findsOneWidget);
|
||||||
expect(find.text('Promotions & Signals'), findsOneWidget);
|
expect(find.text('Promotions & Signals'), findsOneWidget);
|
||||||
expect(find.text('Ideas'), findsOneWidget);
|
expect(find.text('Ideas'), findsOneWidget);
|
||||||
expect(find.text('Moments'), findsOneWidget);
|
expect(find.text('Moments'), findsOneWidget);
|
||||||
|
|||||||
Reference in New Issue
Block a user