Add duplicate profile merge and share deep-link routing
This commit is contained in:
@@ -483,6 +483,179 @@ class LocalRepository extends AsyncNotifier<LocalDataState> {
|
||||
]);
|
||||
}
|
||||
|
||||
/// Merge one person profile into another and rebind related records.
|
||||
Future<void> mergePersonProfiles({
|
||||
required String sourcePersonId,
|
||||
required String targetPersonId,
|
||||
}) async {
|
||||
if (sourcePersonId == targetPersonId) {
|
||||
throw ArgumentError('Source and target profile must be different');
|
||||
}
|
||||
|
||||
final LocalDataState current = _requireState();
|
||||
final PersonProfile? source = _findPersonById(
|
||||
current.people,
|
||||
sourcePersonId,
|
||||
);
|
||||
final PersonProfile? target = _findPersonById(
|
||||
current.people,
|
||||
targetPersonId,
|
||||
);
|
||||
if (source == null || target == null) {
|
||||
throw ArgumentError('Both source and target profiles must exist');
|
||||
}
|
||||
|
||||
final PersonProfile mergedTarget = target.copyWith(
|
||||
affinityScore: target.affinityScore > source.affinityScore
|
||||
? target.affinityScore
|
||||
: source.affinityScore,
|
||||
nextMoment: source.nextMoment.isBefore(target.nextMoment)
|
||||
? source.nextMoment
|
||||
: target.nextMoment,
|
||||
tags: _mergeTags(target.tags, source.tags),
|
||||
notes: _mergeNotes(
|
||||
targetNotes: target.notes,
|
||||
sourceName: source.name,
|
||||
sourceNotes: source.notes,
|
||||
),
|
||||
location: _effectiveLocation(target.location, source.location),
|
||||
);
|
||||
|
||||
final List<PersonProfile> nextPeople = current.people
|
||||
.where((PersonProfile person) => person.id != sourcePersonId)
|
||||
.map(
|
||||
(PersonProfile person) =>
|
||||
person.id == targetPersonId ? mergedTarget : person,
|
||||
)
|
||||
.toList(growable: false);
|
||||
|
||||
final List<RelationshipMoment> updatedMoments = <RelationshipMoment>[];
|
||||
final List<RelationshipMoment> nextMoments = current.moments
|
||||
.map((RelationshipMoment moment) {
|
||||
if (moment.personId != sourcePersonId) {
|
||||
return moment;
|
||||
}
|
||||
final RelationshipMoment merged = moment.copyWith(
|
||||
personId: targetPersonId,
|
||||
);
|
||||
updatedMoments.add(merged);
|
||||
return merged;
|
||||
})
|
||||
.toList(growable: false);
|
||||
|
||||
final List<RelationshipIdea> updatedIdeas = <RelationshipIdea>[];
|
||||
final List<RelationshipIdea> nextIdeas = current.ideas
|
||||
.map((RelationshipIdea idea) {
|
||||
if (idea.personId != sourcePersonId) {
|
||||
return idea;
|
||||
}
|
||||
final RelationshipIdea merged = idea.copyWith(
|
||||
personId: targetPersonId,
|
||||
);
|
||||
updatedIdeas.add(merged);
|
||||
return merged;
|
||||
})
|
||||
.toList(growable: false);
|
||||
|
||||
final List<ReminderRule> updatedReminders = <ReminderRule>[];
|
||||
final List<ReminderRule> nextReminders = current.reminders
|
||||
.map((ReminderRule reminder) {
|
||||
if (reminder.personId != sourcePersonId) {
|
||||
return reminder;
|
||||
}
|
||||
final ReminderRule merged = reminder.copyWith(
|
||||
personId: targetPersonId,
|
||||
);
|
||||
updatedReminders.add(merged);
|
||||
return merged;
|
||||
})
|
||||
.toList(growable: false);
|
||||
|
||||
final List<SourceProfileLink> nextLinks = current.sourceLinks
|
||||
.map((SourceProfileLink link) {
|
||||
if (link.profileId != sourcePersonId) {
|
||||
return link;
|
||||
}
|
||||
return link.copyWith(profileId: targetPersonId);
|
||||
})
|
||||
.toList(growable: false);
|
||||
|
||||
final List<SharedMessageEntry> nextMessages = current.sharedMessages
|
||||
.map((SharedMessageEntry entry) {
|
||||
if (entry.profileId != sourcePersonId) {
|
||||
return entry;
|
||||
}
|
||||
return entry.copyWith(profileId: targetPersonId);
|
||||
})
|
||||
.toList(growable: false);
|
||||
|
||||
final List<SharedInboxEntry> nextInbox = current.sharedInbox
|
||||
.map((SharedInboxEntry entry) {
|
||||
if (!entry.candidateProfileIds.contains(sourcePersonId)) {
|
||||
return entry;
|
||||
}
|
||||
final List<String> candidates = entry.candidateProfileIds
|
||||
.map(
|
||||
(String profileId) =>
|
||||
profileId == sourcePersonId ? targetPersonId : profileId,
|
||||
)
|
||||
.toSet()
|
||||
.toList(growable: false);
|
||||
return entry.copyWith(candidateProfileIds: candidates);
|
||||
})
|
||||
.toList(growable: false);
|
||||
|
||||
await _setState(
|
||||
current.copyWith(
|
||||
people: nextPeople,
|
||||
moments: nextMoments,
|
||||
ideas: nextIdeas,
|
||||
reminders: nextReminders,
|
||||
sourceLinks: nextLinks,
|
||||
sharedMessages: nextMessages,
|
||||
sharedInbox: nextInbox,
|
||||
),
|
||||
);
|
||||
|
||||
await _enqueueChanges(<ChangeEnvelope>[
|
||||
_buildEnvelope(
|
||||
entityType: 'person',
|
||||
entityId: mergedTarget.id,
|
||||
op: ChangeOperation.upsert,
|
||||
payload: _personPayload(mergedTarget),
|
||||
),
|
||||
_buildEnvelope(
|
||||
entityType: 'person',
|
||||
entityId: sourcePersonId,
|
||||
op: ChangeOperation.delete,
|
||||
),
|
||||
...updatedMoments.map(
|
||||
(RelationshipMoment moment) => _buildEnvelope(
|
||||
entityType: 'capture',
|
||||
entityId: moment.id,
|
||||
op: ChangeOperation.upsert,
|
||||
payload: _momentPayload(moment),
|
||||
),
|
||||
),
|
||||
...updatedIdeas.map(
|
||||
(RelationshipIdea idea) => _buildEnvelope(
|
||||
entityType: _ideaEntityType(idea.type),
|
||||
entityId: idea.id,
|
||||
op: ChangeOperation.upsert,
|
||||
payload: _ideaPayload(idea),
|
||||
),
|
||||
),
|
||||
...updatedReminders.map(
|
||||
(ReminderRule reminder) => _buildEnvelope(
|
||||
entityType: 'reminderRule',
|
||||
entityId: reminder.id,
|
||||
op: ChangeOperation.upsert,
|
||||
payload: _reminderPayload(reminder),
|
||||
),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> addMoment({
|
||||
required String personId,
|
||||
required String summary,
|
||||
@@ -1264,6 +1437,49 @@ class LocalRepository extends AsyncNotifier<LocalDataState> {
|
||||
);
|
||||
}
|
||||
|
||||
List<String> _mergeTags(List<String> primary, List<String> secondary) {
|
||||
final List<String> merged = <String>[];
|
||||
final Set<String> seen = <String>{};
|
||||
for (final String raw in <String>[...primary, ...secondary]) {
|
||||
final String tag = raw.trim();
|
||||
if (tag.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
final String normalized = tag.toLowerCase();
|
||||
if (seen.add(normalized)) {
|
||||
merged.add(tag);
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
String _mergeNotes({
|
||||
required String targetNotes,
|
||||
required String sourceName,
|
||||
required String sourceNotes,
|
||||
}) {
|
||||
final String target = targetNotes.trim();
|
||||
final String source = sourceNotes.trim();
|
||||
if (target.isEmpty) {
|
||||
return source;
|
||||
}
|
||||
if (source.isEmpty) {
|
||||
return target;
|
||||
}
|
||||
if (target == source) {
|
||||
return target;
|
||||
}
|
||||
return '$target\n\nMerged from $sourceName:\n$source';
|
||||
}
|
||||
|
||||
String? _effectiveLocation(String? target, String? source) {
|
||||
final String? targetValue = _trimToNull(target);
|
||||
if (targetValue != null) {
|
||||
return targetValue;
|
||||
}
|
||||
return _trimToNull(source);
|
||||
}
|
||||
|
||||
Future<SharedMessageIngestResult> _queueSharedInbox({
|
||||
required LocalDataState current,
|
||||
required String sourceApp,
|
||||
|
||||
@@ -175,6 +175,7 @@ class PeopleView extends ConsumerWidget {
|
||||
children: <Widget>[
|
||||
_PeopleHeader(
|
||||
onAdd: () => _handleAddPerson(context, ref),
|
||||
onMerge: () => _handleMergePeople(context, ref, people),
|
||||
compact: false,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
@@ -229,6 +230,7 @@ class PeopleView extends ConsumerWidget {
|
||||
children: <Widget>[
|
||||
_PeopleHeader(
|
||||
onAdd: () => _handleAddPerson(context, ref),
|
||||
onMerge: () => _handleMergePeople(context, ref, people),
|
||||
compact: true,
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
@@ -331,6 +333,83 @@ class PeopleView extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleMergePeople(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
List<PersonProfile> people,
|
||||
) async {
|
||||
if (people.length < 2) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Need at least two profiles to merge.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final List<PersonProfile> duplicateCandidates = _duplicateCandidates(
|
||||
people,
|
||||
);
|
||||
if (duplicateCandidates.length < 2) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
'No duplicate-name profiles found. Edit names first if needed.',
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final _MergePeopleDraft? draft = await showDialog<_MergePeopleDraft>(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
_MergePeopleDialog(people: duplicateCandidates),
|
||||
);
|
||||
if (draft == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await ref
|
||||
.read(localRepositoryProvider.notifier)
|
||||
.mergePersonProfiles(
|
||||
sourcePersonId: draft.sourcePersonId,
|
||||
targetPersonId: draft.targetPersonId,
|
||||
);
|
||||
ref.read(selectedPersonIdProvider.notifier).select(draft.targetPersonId);
|
||||
if (!context.mounted) {
|
||||
return;
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Profiles merged successfully.')),
|
||||
);
|
||||
}
|
||||
|
||||
List<PersonProfile> _duplicateCandidates(List<PersonProfile> people) {
|
||||
final Map<String, List<PersonProfile>> grouped =
|
||||
<String, List<PersonProfile>>{};
|
||||
for (final PersonProfile person in people) {
|
||||
final String key = _normalizeNameKey(person.name);
|
||||
if (key.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
grouped.putIfAbsent(key, () => <PersonProfile>[]).add(person);
|
||||
}
|
||||
final List<PersonProfile> result = <PersonProfile>[];
|
||||
for (final List<PersonProfile> group in grouped.values) {
|
||||
if (group.length > 1) {
|
||||
result.addAll(group);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String _normalizeNameKey(String value) {
|
||||
return value
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(RegExp(r'[^a-z0-9]+'), ' ')
|
||||
.replaceAll(RegExp(r'\s+'), ' ');
|
||||
}
|
||||
|
||||
Future<String?> _showQuickTextCaptureDialog(
|
||||
BuildContext context, {
|
||||
required String title,
|
||||
@@ -602,9 +681,14 @@ class _PersonDetail extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _PeopleHeader extends StatelessWidget {
|
||||
const _PeopleHeader({required this.onAdd, required this.compact});
|
||||
const _PeopleHeader({
|
||||
required this.onAdd,
|
||||
required this.onMerge,
|
||||
required this.compact,
|
||||
});
|
||||
|
||||
final VoidCallback onAdd;
|
||||
final VoidCallback onMerge;
|
||||
final bool compact;
|
||||
|
||||
@override
|
||||
@@ -628,6 +712,12 @@ class _PeopleHeader extends StatelessWidget {
|
||||
icon: const Icon(Icons.person_add_alt_1_rounded),
|
||||
label: const Text('Add person'),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
OutlinedButton.icon(
|
||||
onPressed: onMerge,
|
||||
icon: const Icon(Icons.merge_type_rounded),
|
||||
label: const Text('Merge duplicates'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -654,6 +744,12 @@ class _PeopleHeader extends StatelessWidget {
|
||||
icon: const Icon(Icons.person_add_alt_1_rounded),
|
||||
label: const Text('Add'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
OutlinedButton.icon(
|
||||
onPressed: onMerge,
|
||||
icon: const Icon(Icons.merge_type_rounded),
|
||||
label: const Text('Merge'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -851,6 +947,138 @@ class _PersonDraft {
|
||||
final String? location;
|
||||
}
|
||||
|
||||
class _MergePeopleDraft {
|
||||
const _MergePeopleDraft({
|
||||
required this.sourcePersonId,
|
||||
required this.targetPersonId,
|
||||
});
|
||||
|
||||
final String sourcePersonId;
|
||||
final String targetPersonId;
|
||||
}
|
||||
|
||||
class _MergePeopleDialog extends StatefulWidget {
|
||||
const _MergePeopleDialog({required this.people});
|
||||
|
||||
final List<PersonProfile> people;
|
||||
|
||||
@override
|
||||
State<_MergePeopleDialog> createState() => _MergePeopleDialogState();
|
||||
}
|
||||
|
||||
class _MergePeopleDialogState extends State<_MergePeopleDialog> {
|
||||
late String _sourcePersonId;
|
||||
late String _targetPersonId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_targetPersonId = widget.people.first.id;
|
||||
_sourcePersonId = widget.people.length > 1
|
||||
? widget.people[1].id
|
||||
: widget.people.first.id;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Merge Duplicate Profiles'),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 420),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Move captures, ideas, reminders, and share links from source into target profile.',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyMedium?.copyWith(color: AppTheme.textSecondary),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<String>(
|
||||
key: ValueKey<String>('target-$_targetPersonId'),
|
||||
initialValue: _targetPersonId,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Keep target profile',
|
||||
),
|
||||
items: widget.people
|
||||
.map(
|
||||
(PersonProfile person) => DropdownMenuItem<String>(
|
||||
value: person.id,
|
||||
child: Text('${person.name} · ${person.relationship}'),
|
||||
),
|
||||
)
|
||||
.toList(growable: false),
|
||||
onChanged: (String? value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_targetPersonId = value;
|
||||
if (_targetPersonId == _sourcePersonId) {
|
||||
_sourcePersonId = widget.people
|
||||
.firstWhere(
|
||||
(PersonProfile person) =>
|
||||
person.id != _targetPersonId,
|
||||
orElse: () => widget.people.first,
|
||||
)
|
||||
.id;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
DropdownButtonFormField<String>(
|
||||
key: ValueKey<String>('source-$_targetPersonId-$_sourcePersonId'),
|
||||
initialValue: _sourcePersonId,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Merge and remove source profile',
|
||||
),
|
||||
items: widget.people
|
||||
.where((PersonProfile person) => person.id != _targetPersonId)
|
||||
.map(
|
||||
(PersonProfile person) => DropdownMenuItem<String>(
|
||||
value: person.id,
|
||||
child: Text('${person.name} · ${person.relationship}'),
|
||||
),
|
||||
)
|
||||
.toList(growable: false),
|
||||
onChanged: (String? value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_sourcePersonId = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
if (_sourcePersonId == _targetPersonId) {
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pop(
|
||||
_MergePeopleDraft(
|
||||
sourcePersonId: _sourcePersonId,
|
||||
targetPersonId: _targetPersonId,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('Merge'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _QuickIdeaDraft {
|
||||
const _QuickIdeaDraft({
|
||||
required this.type,
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:relationship_saver/core/config/app_config.dart';
|
||||
import 'package:relationship_saver/core/config/app_theme.dart';
|
||||
import 'package:relationship_saver/features/auth/session_controller.dart';
|
||||
import 'package:relationship_saver/features/local/local_repository.dart';
|
||||
import 'package:relationship_saver/features/people/people_view.dart';
|
||||
import 'package:relationship_saver/features/reminders/scheduling/reminder_scheduler_provider.dart';
|
||||
import 'package:relationship_saver/features/share_intake/share_inbox_view.dart';
|
||||
import 'package:relationship_saver/features/share_intake/whatsapp_share_parser.dart';
|
||||
@@ -240,6 +241,34 @@ class SettingsView extends ConsumerWidget {
|
||||
? 'Imported and created ${result.profileName}.'
|
||||
: 'Imported to ${result.profileName}.',
|
||||
),
|
||||
action: SnackBarAction(
|
||||
label: result.isQueuedForResolution ? 'Open Inbox' : 'Open Profile',
|
||||
onPressed: () => _openShareDestination(context, ref, result),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openShareDestination(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
SharedMessageIngestResult result,
|
||||
) {
|
||||
if (result.isQueuedForResolution) {
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const ShareInboxView(),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.profileId != null) {
|
||||
ref.read(selectedPersonIdProvider.notifier).select(result.profileId!);
|
||||
}
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const PeopleView(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,26 +48,33 @@ class _WhatsAppShareListenerState extends ConsumerState<WhatsAppShareListener> {
|
||||
try {
|
||||
_mediaSubscription = ReceiveSharingIntent.instance
|
||||
.getMediaStream()
|
||||
.listen(_handleMediaList, onError: (_) {});
|
||||
.listen(
|
||||
(List<SharedMediaFile> files) =>
|
||||
_handleMediaList(files, autoOpenDestination: false),
|
||||
onError: (_) {},
|
||||
);
|
||||
|
||||
final List<SharedMediaFile> initialMedia = await ReceiveSharingIntent
|
||||
.instance
|
||||
.getInitialMedia();
|
||||
if (initialMedia.isNotEmpty) {
|
||||
await _handleMediaList(initialMedia);
|
||||
await _handleMediaList(initialMedia, autoOpenDestination: true);
|
||||
}
|
||||
} catch (_) {
|
||||
// Unsupported platform/plugin state should not break app usage.
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleMediaList(List<SharedMediaFile> files) async {
|
||||
Future<void> _handleMediaList(
|
||||
List<SharedMediaFile> files, {
|
||||
required bool autoOpenDestination,
|
||||
}) async {
|
||||
for (final SharedMediaFile file in files) {
|
||||
final String? rawText = _extractText(file);
|
||||
if (rawText == null) {
|
||||
continue;
|
||||
}
|
||||
await _handleRawText(rawText);
|
||||
await _handleRawText(rawText, autoOpenDestination: autoOpenDestination);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +102,10 @@ class _WhatsAppShareListenerState extends ConsumerState<WhatsAppShareListener> {
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> _handleRawText(String rawText) async {
|
||||
Future<void> _handleRawText(
|
||||
String rawText, {
|
||||
required bool autoOpenDestination,
|
||||
}) async {
|
||||
final String trimmed = rawText.trim();
|
||||
if (trimmed.isEmpty) {
|
||||
return;
|
||||
@@ -130,6 +140,10 @@ class _WhatsAppShareListenerState extends ConsumerState<WhatsAppShareListener> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (autoOpenDestination) {
|
||||
_openShareDestination(result);
|
||||
}
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
@@ -140,16 +154,8 @@ class _WhatsAppShareListenerState extends ConsumerState<WhatsAppShareListener> {
|
||||
: 'Imported from WhatsApp to ${result.profileName}.',
|
||||
),
|
||||
action: SnackBarAction(
|
||||
label: result.isQueuedForResolution ? 'Open Inbox' : 'Open People',
|
||||
onPressed: () {
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => result.isQueuedForResolution
|
||||
? const ShareInboxView()
|
||||
: const PeopleView(),
|
||||
),
|
||||
);
|
||||
},
|
||||
label: result.isQueuedForResolution ? 'Open Inbox' : 'Open Profile',
|
||||
onPressed: () => _openShareDestination(result),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -160,4 +166,27 @@ class _WhatsAppShareListenerState extends ConsumerState<WhatsAppShareListener> {
|
||||
// Best effort.
|
||||
}
|
||||
}
|
||||
|
||||
void _openShareDestination(SharedMessageIngestResult result) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (result.isQueuedForResolution) {
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const ShareInboxView(),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.profileId != null) {
|
||||
ref.read(selectedPersonIdProvider.notifier).select(result.profileId!);
|
||||
}
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const PeopleView(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user