import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/generated/translations.g.dart'; import 'package:immich_mobile/presentation/actions/action.dart'; import 'package:immich_mobile/presentation/widgets/people/partner_user_avatar.widget.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/utils/error_handler.dart'; import 'package:immich_mobile/widgets/common/confirm_dialog.dart'; class PartnerAddAction extends ActionBuilder { const PartnerAddAction(); @override ActionItem create(BuildContext context, WidgetRef ref) => ActionItem(icon: Icons.person_add_rounded, label: context.t.add_partner, onAction: () => _add(context, ref)); Future _add(BuildContext context, WidgetRef ref) async { final partnerService = ref.read(partnerServiceProvider); final authUserId = ref.read(authUserProvider).id; final selected = await showDialog(context: context, builder: (_) => const PartnerSelectionDialog()); if (selected == null) { return; } try { await partnerService.create(sharedById: authUserId, sharedWithId: selected.id); } catch (error, stack) { handleError(error, stack: stack, description: 'Failed to add partner'); } } } class PartnerRemoveAction extends ActionBuilder { const PartnerRemoveAction({required this.sharedWithId, required this.partnerName}); final String sharedWithId; final String partnerName; @override ActionItem create(BuildContext context, WidgetRef ref) => ActionItem(icon: Icons.person_remove_rounded, label: context.t.remove, onAction: () => _remove(context, ref)); Future _remove(BuildContext context, WidgetRef ref) async { final partnerService = ref.read(partnerServiceProvider); final authUserId = ref.read(authUserProvider).id; final confirmed = await showDialog( context: context, builder: (_) => ConfirmDialog( title: context.t.stop_photo_sharing, content: context.t.partner_page_stop_sharing_content(partner: partnerName), ), ); if (confirmed != true) { return; } try { await partnerService.delete(sharedById: authUserId, sharedWithId: sharedWithId); } catch (error, stack) { handleError(error, stack: stack, description: 'Failed to remove partner'); } } } @visibleForTesting final candidatesStateProvider = StreamProvider.autoDispose>( (ref) => ref.watch(partnerServiceProvider).getCandidates(ref.watch(authUserProvider).id), ); @visibleForTesting class PartnerSelectionDialog extends ConsumerWidget { const PartnerSelectionDialog({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final candidatesAsync = ref.watch(candidatesStateProvider); return SimpleDialog( title: Text(context.t.partner_page_select_partner), children: candidatesAsync.when( data: (candidates) { final users = candidates.toList(); if (users.isEmpty) { return [ Padding( padding: const .symmetric(horizontal: 24, vertical: 8), child: Text(context.t.partner_page_no_more_users), ), ]; } return [ for (final candidate in users) SimpleDialogOption( onPressed: () => Navigator.of(context).pop(candidate), child: Row( children: [ Padding( padding: const .only(right: 8), child: PartnerUserAvatar(userId: candidate.id, name: candidate.name), ), Text(candidate.name), ], ), ), ]; }, loading: () => const [ Padding( padding: .all(24), child: Center(child: CircularProgressIndicator()), ), ], error: (error, _) => [ Padding( padding: const .symmetric(horizontal: 24, vertical: 8), child: Text(context.t.error_loading_partners(error: error)), ), ], ), ); } }