✨ Public contact method
This commit is contained in:
		| @@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/auth.dart'; | ||||
| import 'package:island/models/account.dart'; | ||||
| @@ -479,6 +480,7 @@ class AccountSettingsScreen extends HookConsumerWidget { | ||||
|                       ); | ||||
|                     }, | ||||
|                   ), | ||||
|                   const Gap(8), | ||||
|                 ] | ||||
|                 : null, | ||||
|       ), | ||||
|   | ||||
| @@ -62,6 +62,32 @@ class ContactMethodSheet extends HookConsumerWidget { | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     Future<void> makeContactMethodPublic() async { | ||||
|       try { | ||||
|         showLoadingModal(context); | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post('/id/accounts/me/contacts/${contact.id}/public'); | ||||
|         if (context.mounted) Navigator.pop(context, true); | ||||
|       } catch (err) { | ||||
|         showErrorAlert(err); | ||||
|       } finally { | ||||
|         if (context.mounted) hideLoadingModal(context); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     Future<void> makeContactMethodPrivate() async { | ||||
|       try { | ||||
|         showLoadingModal(context); | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.delete('/id/accounts/me/contacts/${contact.id}/public'); | ||||
|         if (context.mounted) Navigator.pop(context, true); | ||||
|       } catch (err) { | ||||
|         showErrorAlert(err); | ||||
|       } finally { | ||||
|         if (context.mounted) hideLoadingModal(context); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return SheetScaffold( | ||||
|       titleText: 'contactMethod'.tr(), | ||||
|       child: Column( | ||||
| @@ -111,6 +137,27 @@ class ContactMethodSheet extends HookConsumerWidget { | ||||
|                         backgroundColor: Theme.of(context).colorScheme.tertiary, | ||||
|                       ), | ||||
|                     ), | ||||
|                   if (contact.isPublic) | ||||
|                     Padding( | ||||
|                       padding: const EdgeInsets.only(left: 8.0), | ||||
|                       child: Badge( | ||||
|                         label: Text('contactMethodPublic'.tr()), | ||||
|                         textColor: Theme.of(context).colorScheme.onPrimary, | ||||
|                         backgroundColor: Theme.of(context).colorScheme.primary, | ||||
|                       ), | ||||
|                     ), | ||||
|                   if (!contact.isPublic) | ||||
|                     Padding( | ||||
|                       padding: const EdgeInsets.only(left: 8.0), | ||||
|                       child: Badge( | ||||
|                         label: Text('contactMethodPrivate'.tr()), | ||||
|                         textColor: Theme.of(context).colorScheme.onSurface, | ||||
|                         backgroundColor: | ||||
|                             Theme.of( | ||||
|                               context, | ||||
|                             ).colorScheme.surfaceContainerHighest, | ||||
|                       ), | ||||
|                     ), | ||||
|                 ], | ||||
|               ), | ||||
|             ], | ||||
| @@ -130,6 +177,20 @@ class ContactMethodSheet extends HookConsumerWidget { | ||||
|               onTap: setContactMethodAsPrimary, | ||||
|               contentPadding: EdgeInsets.symmetric(horizontal: 20), | ||||
|             ), | ||||
|           if (contact.verifiedAt != null && !contact.isPublic) | ||||
|             ListTile( | ||||
|               leading: const Icon(Symbols.public), | ||||
|               title: Text('contactMethodMakePublic').tr(), | ||||
|               onTap: makeContactMethodPublic, | ||||
|               contentPadding: EdgeInsets.symmetric(horizontal: 20), | ||||
|             ), | ||||
|           if (contact.verifiedAt != null && contact.isPublic) | ||||
|             ListTile( | ||||
|               leading: const Icon(Symbols.visibility_off), | ||||
|               title: Text('contactMethodMakePrivate').tr(), | ||||
|               onTap: makeContactMethodPrivate, | ||||
|               contentPadding: EdgeInsets.symmetric(horizontal: 20), | ||||
|             ), | ||||
|           ListTile( | ||||
|             leading: const Icon(Symbols.delete), | ||||
|             title: Text('contactMethodDelete').tr(), | ||||
|   | ||||
| @@ -321,6 +321,59 @@ class _AccountProfileLinks extends StatelessWidget { | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _AccountProfileContacts extends StatelessWidget { | ||||
|   final SnAccount data; | ||||
|  | ||||
|   const _AccountProfileContacts({required this.data}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final publicContacts = data.contacts.where((c) => c.isPublic).toList(); | ||||
|     if (publicContacts.isEmpty) return const SizedBox.shrink(); | ||||
|  | ||||
|     return Card( | ||||
|       child: Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Text( | ||||
|             'contactMethod', | ||||
|           ).tr().bold().padding(horizontal: 24, top: 12, bottom: 4), | ||||
|           for (final contact in publicContacts) | ||||
|             ListTile( | ||||
|               title: Text(contact.content), | ||||
|               subtitle: Text(switch (contact.type) { | ||||
|                 0 => 'contactMethodTypeEmail'.tr(), | ||||
|                 1 => 'contactMethodTypePhone'.tr(), | ||||
|                 _ => 'contactMethodTypeAddress'.tr(), | ||||
|               }), | ||||
|               leading: Icon(switch (contact.type) { | ||||
|                 0 => Symbols.mail, | ||||
|                 1 => Symbols.phone, | ||||
|                 _ => Symbols.home, | ||||
|               }), | ||||
|               contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||
|               trailing: const Icon(Symbols.chevron_right), | ||||
|               shape: RoundedRectangleBorder( | ||||
|                 borderRadius: const BorderRadius.all(Radius.circular(8)), | ||||
|               ), | ||||
|               onTap: () { | ||||
|                 switch (contact.type) { | ||||
|                   case 0: | ||||
|                     launchUrlString('mailto:${contact.content}'); | ||||
|                   case 1: | ||||
|                     launchUrlString('tel:${contact.content}'); | ||||
|                   default: | ||||
|                     // For address, maybe copy to clipboard or do nothing | ||||
|                     Clipboard.setData(ClipboardData(text: contact.content)); | ||||
|                 } | ||||
|               }, | ||||
|             ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _AccountPublisherList extends StatelessWidget { | ||||
|   final List<SnPublisher> publishers; | ||||
|  | ||||
| @@ -792,6 +845,10 @@ class AccountProfileScreen extends HookConsumerWidget { | ||||
|                               SliverToBoxAdapter( | ||||
|                                 child: _AccountProfileLinks(data: data), | ||||
|                               ), | ||||
|                             if (data.contacts.any((c) => c.isPublic)) | ||||
|                               SliverToBoxAdapter( | ||||
|                                 child: _AccountProfileContacts(data: data), | ||||
|                               ), | ||||
|                             SliverToBoxAdapter( | ||||
|                               child: _AccountProfileDetail(data: data), | ||||
|                             ), | ||||
| @@ -916,6 +973,12 @@ class AccountProfileScreen extends HookConsumerWidget { | ||||
|                             data: data, | ||||
|                           ).padding(horizontal: 4), | ||||
|                         ), | ||||
|                       if (data.contacts.any((c) => c.isPublic)) | ||||
|                         SliverToBoxAdapter( | ||||
|                           child: _AccountProfileContacts( | ||||
|                             data: data, | ||||
|                           ).padding(horizontal: 4), | ||||
|                         ), | ||||
|                       SliverToBoxAdapter( | ||||
|                         child: _AccountPublisherList( | ||||
|                           publishers: accountPublishers.value ?? [], | ||||
|   | ||||
		Reference in New Issue
	
	Block a user