Compare commits
	
		
			3 Commits
		
	
	
		
			4499d4ec8e
			...
			3.1.0+114
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 25ae18d6a9 | |||
| 18db50d80c | |||
| 903008d397 | 
| @@ -698,5 +698,9 @@ | ||||
|   "postForwardingTo": "Forwarding to", | ||||
|   "postReplyingTo": "Replying to", | ||||
|   "postEditing": "You are editing an existing post", | ||||
|   "postArticle": "Article" | ||||
|   "postArticle": "Article", | ||||
|   "aboutDeviceName": "Device Name", | ||||
|   "aboutDeviceIdentifier": "Device Identifier", | ||||
|   "donate": "Donate", | ||||
|   "donateDescription": "Support us to continue developing the Solar Network and keep the server up and running." | ||||
| } | ||||
| @@ -10,7 +10,7 @@ part 'config.g.dart'; | ||||
|  | ||||
| const kTokenPairStoreKey = 'dyn_user_tk'; | ||||
|  | ||||
| const kNetworkServerDefault = 'https://nt.solian.app'; | ||||
| const kNetworkServerDefault = 'https://api.solian.app'; | ||||
| const kNetworkServerStoreKey = 'app_server_url'; | ||||
|  | ||||
| const kAppbarTransparentStoreKey = 'app_bar_transparent'; | ||||
| @@ -82,7 +82,7 @@ class AppSettingsNotifier extends _$AppSettingsNotifier { | ||||
|   Size? _getWindowSizeFromPrefs(SharedPreferences prefs) { | ||||
|     final sizeString = prefs.getString(kAppWindowSize); | ||||
|     if (sizeString == null) return null; | ||||
|      | ||||
|  | ||||
|     try { | ||||
|       final parts = sizeString.split(','); | ||||
|       if (parts.length == 2) { | ||||
|   | ||||
| @@ -39,7 +39,7 @@ class WebFeedNotifier | ||||
|     try { | ||||
|       final client = ref.read(apiClientProvider); | ||||
|       final response = await client.get( | ||||
|         '/publishers/${arg.pubName}/feeds/${arg.feedId}', | ||||
|         '/sphere/publishers/${arg.pubName}/feeds/${arg.feedId}', | ||||
|       ); | ||||
|       return SnWebFeed.fromJson(response.data); | ||||
|     } catch (e) { | ||||
| @@ -51,7 +51,7 @@ class WebFeedNotifier | ||||
|     state = const AsyncValue.loading(); | ||||
|     try { | ||||
|       final client = ref.read(apiClientProvider); | ||||
|       final url = '/publishers/${feed.publisherId}/feeds'; | ||||
|       final url = '/sphere/publishers/${feed.publisherId}/feeds'; | ||||
|  | ||||
|       final response = | ||||
|           feed.id.isEmpty | ||||
| @@ -98,7 +98,7 @@ class WebFeedNotifier | ||||
|     try { | ||||
|       final client = ref.read(apiClientProvider); | ||||
|       await client.post( | ||||
|         '/publishers/${arg.pubName}/feeds/$feedId/scrap', | ||||
|         '/sphere/publishers/${arg.pubName}/feeds/$feedId/scrap', | ||||
|         options: Options( | ||||
|           sendTimeout: const Duration(seconds: 60), | ||||
|           receiveTimeout: const Duration(seconds: 180), | ||||
| @@ -107,7 +107,7 @@ class WebFeedNotifier | ||||
|  | ||||
|       // Reload the feed | ||||
|       final response = await client.get( | ||||
|         '/publishers/${arg.pubName}/feeds/$feedId', | ||||
|         '/sphere/publishers/${arg.pubName}/feeds/$feedId', | ||||
|       ); | ||||
|       state = AsyncValue.data(SnWebFeed.fromJson(response.data)); | ||||
|     } catch (error, stackTrace) { | ||||
|   | ||||
| @@ -1,18 +1,19 @@ | ||||
| import 'dart:io'; | ||||
|  | ||||
| import 'package:device_info_plus/device_info_plus.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/pods/network.dart'; | ||||
| import 'package:island/services/notify.dart'; | ||||
| import 'package:island/services/udid.native.dart'; | ||||
| import 'package:island/widgets/alert.dart'; | ||||
| import 'package:island/widgets/app_scaffold.dart'; | ||||
| import 'package:material_symbols_icons/symbols.dart'; | ||||
| import 'package:package_info_plus/package_info_plus.dart'; | ||||
| import 'package:styled_widget/styled_widget.dart'; | ||||
| import 'package:url_launcher/url_launcher.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:url_launcher/url_launcher_string.dart'; | ||||
|  | ||||
| class AboutScreen extends ConsumerStatefulWidget { | ||||
|   const AboutScreen({super.key}); | ||||
| @@ -168,34 +169,16 @@ class _AboutScreenState extends ConsumerState<AboutScreen> { | ||||
|                           _buildInfoItem( | ||||
|                             context, | ||||
|                             icon: Symbols.label, | ||||
|                             label: 'Device Name', | ||||
|                             label: 'aboutDeviceName'.tr(), | ||||
|                             value: _deviceInfo?.data['name'], | ||||
|                           ), | ||||
|                           _buildInfoItem( | ||||
|                             context, | ||||
|                             icon: Symbols.fingerprint, | ||||
|                             label: 'Device Identifier', | ||||
|                             label: 'aboutDeviceIdentifier'.tr(), | ||||
|                             value: _deviceUdid ?? 'N/A', | ||||
|                             copyable: true, | ||||
|                           ), | ||||
|                           const Divider(height: 1), | ||||
|                           _buildListTile( | ||||
|                             context, | ||||
|                             icon: Symbols.notifications_active, | ||||
|                             title: 'Reactivate Push Notifications', | ||||
|                             onTap: () async { | ||||
|                               showLoadingModal(context); | ||||
|                               try { | ||||
|                                 await subscribePushNotification( | ||||
|                                   ref.watch(apiClientProvider), | ||||
|                                 ); | ||||
|                               } catch (err) { | ||||
|                                 showErrorAlert(err); | ||||
|                               } finally { | ||||
|                                 if (context.mounted) hideLoadingModal(context); | ||||
|                               } | ||||
|                             }, | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|  | ||||
| @@ -266,6 +249,18 @@ class _AboutScreenState extends ConsumerState<AboutScreen> { | ||||
|                                 'https://github.com/Solsynth/Solian/blob/v3/LICENSE.txt', | ||||
|                               ), | ||||
|                         ), | ||||
|                         if (kIsWeb || !(Platform.isMacOS || Platform.isIOS)) | ||||
|                           _buildListTile( | ||||
|                             context, | ||||
|                             icon: Symbols.favorite, | ||||
|                             title: 'donate'.tr(), | ||||
|                             subtitle: 'donateDescription'.tr(), | ||||
|                             onTap: () { | ||||
|                               launchUrlString( | ||||
|                                 'https://afdian.com/@littlesheep', | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                       ], | ||||
|                     ), | ||||
|  | ||||
|   | ||||
| @@ -106,7 +106,7 @@ class AuthFactorSheet extends HookConsumerWidget { | ||||
|         showLoadingModal(context); | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post( | ||||
|           '/accounts/me/factors/${factor.id}/enable', | ||||
|           '/id/accounts/me/factors/${factor.id}/enable', | ||||
|           data: jsonEncode(password), | ||||
|         ); | ||||
|         if (context.mounted) Navigator.pop(context, true); | ||||
| @@ -193,7 +193,7 @@ class AuthFactorNewSheet extends HookConsumerWidget { | ||||
|         showLoadingModal(context); | ||||
|         final apiClient = ref.read(apiClientProvider); | ||||
|         final resp = await apiClient.post( | ||||
|           '/accounts/me/factors', | ||||
|           '/id/accounts/me/factors', | ||||
|           data: {'type': factorType.value, 'secret': secretController.text}, | ||||
|         ); | ||||
|         final factor = SnAuthFactor.fromJson(resp.data); | ||||
|   | ||||
| @@ -174,7 +174,7 @@ class AccountConnectionNewSheet extends HookConsumerWidget { | ||||
|             if (context.mounted) showLoadingModal(context); | ||||
|  | ||||
|             await client.post( | ||||
|               '/auth/connect/apple/mobile', | ||||
|               '/id/auth/connect/apple/mobile', | ||||
|               data: { | ||||
|                 'identity_token': credential.identityToken!, | ||||
|                 'authorization_code': credential.authorizationCode, | ||||
| @@ -336,7 +336,7 @@ class AccountConnectionsSheet extends HookConsumerWidget { | ||||
|                                 try { | ||||
|                                   final client = ref.read(apiClientProvider); | ||||
|                                   await client.delete( | ||||
|                                     '/accounts/me/connections/${connection.id}', | ||||
|                                     '/id/accounts/me/connections/${connection.id}', | ||||
|                                   ); | ||||
|                                   ref.invalidate(accountConnectionsProvider); | ||||
|                                   return true; | ||||
|   | ||||
| @@ -160,7 +160,7 @@ class ContactMethodNewSheet extends HookConsumerWidget { | ||||
|         showLoadingModal(context); | ||||
|         final apiClient = ref.read(apiClientProvider); | ||||
|         await apiClient.post( | ||||
|           '/accounts/me/contacts', | ||||
|           '/id/accounts/me/contacts', | ||||
|           data: {'type': contactType.value, 'content': contentController.text}, | ||||
|         ); | ||||
|         if (context.mounted) { | ||||
|   | ||||
| @@ -39,14 +39,14 @@ Future<SnAccount> account(Ref ref, String uname) async { | ||||
|     } | ||||
|   } | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   final resp = await apiClient.get("/accounts/$uname"); | ||||
|   final resp = await apiClient.get("/id/accounts/$uname"); | ||||
|   return SnAccount.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| @riverpod | ||||
| Future<List<SnAccountBadge>> accountBadges(Ref ref, String uname) async { | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   final resp = await apiClient.get("/accounts/$uname/badges"); | ||||
|   final resp = await apiClient.get("/id/accounts/$uname/badges"); | ||||
|   return List<SnAccountBadge>.from( | ||||
|     resp.data.map((x) => SnAccountBadge.fromJson(x)), | ||||
|   ); | ||||
| @@ -78,7 +78,7 @@ Future<SnChatRoom?> accountDirectChat(Ref ref, String uname) async { | ||||
|   final account = await ref.watch(accountProvider(uname).future); | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   try { | ||||
|     final resp = await apiClient.get("/chat/direct/${account.id}"); | ||||
|     final resp = await apiClient.get("/sphere/chat/direct/${account.id}"); | ||||
|     return SnChatRoom.fromJson(resp.data); | ||||
|   } catch (err) { | ||||
|     if (err is DioException && err.response?.statusCode == 404) { | ||||
| @@ -95,7 +95,7 @@ Future<SnRelationship?> accountRelationship(Ref ref, String uname) async { | ||||
|   final account = await ref.watch(accountProvider(uname).future); | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   try { | ||||
|     final resp = await apiClient.get("/relationships/${account.id}"); | ||||
|     final resp = await apiClient.get("/id/relationships/${account.id}"); | ||||
|     return SnRelationship.fromJson(resp.data); | ||||
|   } catch (err) { | ||||
|     if (err is DioException && err.response?.statusCode == 404) { | ||||
| @@ -174,7 +174,7 @@ class AccountProfileScreen extends HookConsumerWidget { | ||||
|       try { | ||||
|         final client = ref.watch(apiClientProvider); | ||||
|         final resp = await client.post( | ||||
|           '/chat/direct', | ||||
|           '/sphere/chat/direct', | ||||
|           data: {'related_user_id': account.value!.id}, | ||||
|         ); | ||||
|         final chat = SnChatRoom.fromJson(resp.data); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ part of 'profile.dart'; | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$accountHash() => r'd2b0579617e6264452d98f47f695a9cdf45b24ec'; | ||||
| String _$accountHash() => r'ce7264a04f69e32a5cb07bc10ca5fa47ae1fddaa'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
| @@ -145,7 +145,7 @@ class _AccountProviderElement | ||||
|   String get uname => (origin as AccountProvider).uname; | ||||
| } | ||||
|  | ||||
| String _$accountBadgesHash() => r'4bfe5fb0d6ac0d4cde4563460bde289289188f6d'; | ||||
| String _$accountBadgesHash() => r'1de05e122c23ff2c6ac6d318977165761e2ad177'; | ||||
|  | ||||
| /// See also [accountBadges]. | ||||
| @ProviderFor(accountBadges) | ||||
| @@ -395,7 +395,7 @@ class _AccountAppbarForcegroundColorProviderElement | ||||
|   String get uname => (origin as AccountAppbarForcegroundColorProvider).uname; | ||||
| } | ||||
|  | ||||
| String _$accountDirectChatHash() => r'3d28c8ba8079159f724fe3cd47bbe00db55cedcc'; | ||||
| String _$accountDirectChatHash() => r'149ea3a3730672cfbbb8c16fe1f2caa0bb9f0e17'; | ||||
|  | ||||
| /// See also [accountDirectChat]. | ||||
| @ProviderFor(accountDirectChat) | ||||
| @@ -517,7 +517,7 @@ class _AccountDirectChatProviderElement | ||||
| } | ||||
|  | ||||
| String _$accountRelationshipHash() => | ||||
|     r'0be2420e1f6a65b8dcead9617191471924aaf232'; | ||||
|     r'9a3a4e8c6c6706f73df95feccb86736fcad33f30'; | ||||
|  | ||||
| /// See also [accountRelationship]. | ||||
| @ProviderFor(accountRelationship) | ||||
|   | ||||
| @@ -42,7 +42,7 @@ class RelationshipListNotifier extends _$RelationshipListNotifier | ||||
|     final take = 20; | ||||
|  | ||||
|     final response = await client.get( | ||||
|       '/relationships', | ||||
|       '/id/relationships', | ||||
|       queryParameters: {'offset': offset, 'take': take}, | ||||
|     ); | ||||
|  | ||||
| @@ -235,7 +235,7 @@ class RelationshipScreen extends HookConsumerWidget { | ||||
|         submitting.value = true; | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post( | ||||
|           '/relationships/${relationship.accountId}/friends/${isAccept ? 'accept' : 'decline'}', | ||||
|           '/id/relationships/${relationship.accountId}/friends/${isAccept ? 'accept' : 'decline'}', | ||||
|         ); | ||||
|         relationshipNotifier.forceRefresh(); | ||||
|         if (!context.mounted) return; | ||||
| @@ -262,7 +262,7 @@ class RelationshipScreen extends HookConsumerWidget { | ||||
|     ) async { | ||||
|       final client = ref.read(apiClientProvider); | ||||
|       await client.patch( | ||||
|         '/relationships/${relationship.accountId}', | ||||
|         '/id/relationships/${relationship.accountId}', | ||||
|         data: {'status': newStatus}, | ||||
|       ); | ||||
|       relationshipNotifier.forceRefresh(); | ||||
|   | ||||
| @@ -27,7 +27,7 @@ final sentFriendRequestProvider = | ||||
| typedef SentFriendRequestRef = | ||||
|     AutoDisposeFutureProviderRef<List<SnRelationship>>; | ||||
| String _$relationshipListNotifierHash() => | ||||
|     r'560410cba6e4c26affd91aa86b3666319bd31f24'; | ||||
|     r'0a134ce69489a4f2002d2223853855b6f22e4e9f'; | ||||
|  | ||||
| /// See also [RelationshipListNotifier]. | ||||
| @ProviderFor(RelationshipListNotifier) | ||||
|   | ||||
| @@ -298,6 +298,7 @@ class ChatListScreen extends HookConsumerWidget { | ||||
|             ), | ||||
|             onPressed: () { | ||||
|               showModalBottomSheet( | ||||
|                 useRootNavigator: true, | ||||
|                 isScrollControlled: true, | ||||
|                 context: context, | ||||
|                 builder: (context) => const _ChatInvitesSheet(), | ||||
| @@ -608,127 +609,129 @@ class EditChatScreen extends HookConsumerWidget { | ||||
|         title: Text(id == null ? 'createChatRoom' : 'editChatRoom').tr(), | ||||
|         leading: const PageBackButton(), | ||||
|       ), | ||||
|       body: Column( | ||||
|         children: [ | ||||
|           RealmSelectionDropdown( | ||||
|             value: currentRealm.value, | ||||
|             realms: joinedRealms.when( | ||||
|               data: (realms) => realms, | ||||
|               loading: () => [], | ||||
|               error: (_, _) => [], | ||||
|       body: SingleChildScrollView( | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             RealmSelectionDropdown( | ||||
|               value: currentRealm.value, | ||||
|               realms: joinedRealms.when( | ||||
|                 data: (realms) => realms, | ||||
|                 loading: () => [], | ||||
|                 error: (_, _) => [], | ||||
|               ), | ||||
|               onChanged: (SnRealm? value) { | ||||
|                 currentRealm.value = value; | ||||
|               }, | ||||
|               isLoading: joinedRealms.isLoading, | ||||
|               error: joinedRealms.error?.toString(), | ||||
|             ), | ||||
|             onChanged: (SnRealm? value) { | ||||
|               currentRealm.value = value; | ||||
|             }, | ||||
|             isLoading: joinedRealms.isLoading, | ||||
|             error: joinedRealms.error?.toString(), | ||||
|           ), | ||||
|           AspectRatio( | ||||
|             aspectRatio: 16 / 7, | ||||
|             child: Stack( | ||||
|               clipBehavior: Clip.none, | ||||
|               fit: StackFit.expand, | ||||
|               children: [ | ||||
|                 GestureDetector( | ||||
|                   child: Container( | ||||
|                     color: Theme.of(context).colorScheme.surfaceContainerHigh, | ||||
|                     child: | ||||
|                         background.value != null | ||||
|                             ? CloudFileWidget( | ||||
|                               item: background.value!, | ||||
|                               fit: BoxFit.cover, | ||||
|                             ) | ||||
|                             : const SizedBox.shrink(), | ||||
|                   ), | ||||
|                   onTap: () { | ||||
|                     setPicture('background'); | ||||
|                   }, | ||||
|                 ), | ||||
|                 Positioned( | ||||
|                   left: 20, | ||||
|                   bottom: -32, | ||||
|                   child: GestureDetector( | ||||
|                     child: ProfilePictureWidget( | ||||
|                       fileId: picture.value?.id, | ||||
|                       radius: 40, | ||||
|                       fallbackIcon: Symbols.group, | ||||
|             AspectRatio( | ||||
|               aspectRatio: 16 / 7, | ||||
|               child: Stack( | ||||
|                 clipBehavior: Clip.none, | ||||
|                 fit: StackFit.expand, | ||||
|                 children: [ | ||||
|                   GestureDetector( | ||||
|                     child: Container( | ||||
|                       color: Theme.of(context).colorScheme.surfaceContainerHigh, | ||||
|                       child: | ||||
|                           background.value != null | ||||
|                               ? CloudFileWidget( | ||||
|                                 item: background.value!, | ||||
|                                 fit: BoxFit.cover, | ||||
|                               ) | ||||
|                               : const SizedBox.shrink(), | ||||
|                     ), | ||||
|                     onTap: () { | ||||
|                       setPicture('picture'); | ||||
|                       setPicture('background'); | ||||
|                     }, | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|                   Positioned( | ||||
|                     left: 20, | ||||
|                     bottom: -32, | ||||
|                     child: GestureDetector( | ||||
|                       child: ProfilePictureWidget( | ||||
|                         fileId: picture.value?.id, | ||||
|                         radius: 40, | ||||
|                         fallbackIcon: Symbols.group, | ||||
|                       ), | ||||
|                       onTap: () { | ||||
|                         setPicture('picture'); | ||||
|                       }, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ).padding(bottom: 32), | ||||
|             Form( | ||||
|               key: formKey, | ||||
|               child: Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 children: [ | ||||
|                   TextFormField( | ||||
|                     controller: nameController, | ||||
|                     decoration: const InputDecoration(labelText: 'Name'), | ||||
|                     onTapOutside: | ||||
|                         (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                   ), | ||||
|                   const SizedBox(height: 16), | ||||
|                   TextFormField( | ||||
|                     controller: descriptionController, | ||||
|                     decoration: const InputDecoration( | ||||
|                       labelText: 'Description', | ||||
|                       alignLabelWithHint: true, | ||||
|                     ), | ||||
|                     minLines: 3, | ||||
|                     maxLines: null, | ||||
|                     onTapOutside: | ||||
|                         (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                   ), | ||||
|                   const SizedBox(height: 16), | ||||
|                   Card( | ||||
|                     margin: EdgeInsets.zero, | ||||
|                     child: Column( | ||||
|                       children: [ | ||||
|                         CheckboxListTile( | ||||
|                           secondary: const Icon(Symbols.public), | ||||
|                           title: Text('publicChat').tr(), | ||||
|                           subtitle: Text('publicChatDescription').tr(), | ||||
|                           value: isPublic.value, | ||||
|                           onChanged: (value) { | ||||
|                             isPublic.value = value ?? true; | ||||
|                           }, | ||||
|                           shape: RoundedRectangleBorder( | ||||
|                             borderRadius: BorderRadius.circular(8), | ||||
|                           ), | ||||
|                         ), | ||||
|                         CheckboxListTile( | ||||
|                           secondary: const Icon(Symbols.travel_explore), | ||||
|                           title: Text('communityChat').tr(), | ||||
|                           subtitle: Text('communityChatDescription').tr(), | ||||
|                           value: isCommunity.value, | ||||
|                           onChanged: (value) { | ||||
|                             isCommunity.value = value ?? false; | ||||
|                           }, | ||||
|                           shape: RoundedRectangleBorder( | ||||
|                             borderRadius: BorderRadius.circular(8), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ], | ||||
|                     ), | ||||
|                   ), | ||||
|                   const SizedBox(height: 16), | ||||
|                   Align( | ||||
|                     alignment: Alignment.centerRight, | ||||
|                     child: TextButton.icon( | ||||
|                       onPressed: submitting.value ? null : performAction, | ||||
|                       label: const Text('Save'), | ||||
|                       icon: const Icon(Symbols.save), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ).padding(all: 24), | ||||
|             ), | ||||
|           ).padding(bottom: 32), | ||||
|           Form( | ||||
|             key: formKey, | ||||
|             child: Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 TextFormField( | ||||
|                   controller: nameController, | ||||
|                   decoration: const InputDecoration(labelText: 'Name'), | ||||
|                   onTapOutside: | ||||
|                       (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 TextFormField( | ||||
|                   controller: descriptionController, | ||||
|                   decoration: const InputDecoration( | ||||
|                     labelText: 'Description', | ||||
|                     alignLabelWithHint: true, | ||||
|                   ), | ||||
|                   minLines: 3, | ||||
|                   maxLines: null, | ||||
|                   onTapOutside: | ||||
|                       (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 Card( | ||||
|                   margin: EdgeInsets.zero, | ||||
|                   child: Column( | ||||
|                     children: [ | ||||
|                       CheckboxListTile( | ||||
|                         secondary: const Icon(Symbols.public), | ||||
|                         title: Text('publicChat').tr(), | ||||
|                         subtitle: Text('publicChatDescription').tr(), | ||||
|                         value: isPublic.value, | ||||
|                         onChanged: (value) { | ||||
|                           isPublic.value = value ?? true; | ||||
|                         }, | ||||
|                         shape: RoundedRectangleBorder( | ||||
|                           borderRadius: BorderRadius.circular(8), | ||||
|                         ), | ||||
|                       ), | ||||
|                       CheckboxListTile( | ||||
|                         secondary: const Icon(Symbols.travel_explore), | ||||
|                         title: Text('communityChat').tr(), | ||||
|                         subtitle: Text('communityChatDescription').tr(), | ||||
|                         value: isCommunity.value, | ||||
|                         onChanged: (value) { | ||||
|                           isCommunity.value = value ?? false; | ||||
|                         }, | ||||
|                         shape: RoundedRectangleBorder( | ||||
|                           borderRadius: BorderRadius.circular(8), | ||||
|                         ), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 Align( | ||||
|                   alignment: Alignment.centerRight, | ||||
|                   child: TextButton.icon( | ||||
|                     onPressed: submitting.value ? null : performAction, | ||||
|                     label: const Text('Save'), | ||||
|                     icon: const Icon(Symbols.save), | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|             ).padding(all: 24), | ||||
|           ), | ||||
|         ], | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -389,7 +389,10 @@ class _ChatRoomActionMenu extends HookConsumerWidget { | ||||
|             if ((chatIdentity.value?.role ?? 0) >= 50) | ||||
|               PopupMenuItem( | ||||
|                 onTap: () { | ||||
|                   context.pushReplacement('/sphere/chat/$id/edit'); | ||||
|                   context.pushReplacementNamed( | ||||
|                     'chatEdit', | ||||
|                     pathParameters: {'id': id}, | ||||
|                   ); | ||||
|                 }, | ||||
|                 child: Row( | ||||
|                   children: [ | ||||
| @@ -502,7 +505,7 @@ class ChatMemberNotifier extends StateNotifier<ChatRoomMemberState> { | ||||
|  | ||||
|     try { | ||||
|       final response = await _apiClient.get( | ||||
|         '/chat/$roomId/members', | ||||
|         '/sphere/chat/$roomId/members', | ||||
|         queryParameters: {'offset': offset, 'take': take}, | ||||
|       ); | ||||
|  | ||||
| @@ -540,7 +543,7 @@ class ChatMemberListNotifier extends _$ChatMemberListNotifier | ||||
|  | ||||
|     final apiClient = ref.watch(apiClientProvider); | ||||
|     final response = await apiClient.get( | ||||
|       '/chat/$roomId/members', | ||||
|       '/sphere/chat/$roomId/members', | ||||
|       queryParameters: {'offset': offset, 'take': take}, | ||||
|     ); | ||||
|  | ||||
| @@ -592,7 +595,7 @@ class _ChatMemberListSheet extends HookConsumerWidget { | ||||
|       try { | ||||
|         final apiClient = ref.watch(apiClientProvider); | ||||
|         await apiClient.post( | ||||
|           '/chat/invites/$roomId', | ||||
|           '/sphere/chat/invites/$roomId', | ||||
|           data: {'related_user_id': result.id, 'role': 0}, | ||||
|         ); | ||||
|         // Refresh both providers | ||||
| @@ -846,7 +849,7 @@ class _ChatMemberRoleSheet extends HookConsumerWidget { | ||||
|  | ||||
|                       final apiClient = ref.read(apiClientProvider); | ||||
|                       await apiClient.patch( | ||||
|                         '/chat/$roomId/members/${member.accountId}/role', | ||||
|                         '/sphere/chat/$roomId/members/${member.accountId}/role', | ||||
|                         data: newRole, | ||||
|                       ); | ||||
|  | ||||
|   | ||||
| @@ -83,7 +83,7 @@ class PublisherMemberListNotifier extends _$PublisherMemberListNotifier | ||||
|     final offset = cursor != null ? int.parse(cursor) : 0; | ||||
|  | ||||
|     final response = await apiClient.get( | ||||
|       '/publishers/$uname/members', | ||||
|       '/sphere/publishers/$uname/members', | ||||
|       queryParameters: {'offset': offset, 'take': _pageSize}, | ||||
|     ); | ||||
|  | ||||
| @@ -143,14 +143,19 @@ class CreatorHubScreen extends HookConsumerWidget { | ||||
|     ); | ||||
|  | ||||
|     void updatePublisher() { | ||||
|       context.pushNamed('creatorEdit', pathParameters: {'name': currentPublisher.value!.name}).then(( | ||||
|         value, | ||||
|       ) async { | ||||
|         if (value == null) return; | ||||
|         final data = await ref.refresh(publishersManagedProvider.future); | ||||
|         currentPublisher.value = | ||||
|             data.where((e) => e.id == currentPublisher.value!.id).firstOrNull; | ||||
|       }); | ||||
|       context | ||||
|           .pushNamed( | ||||
|             'creatorEdit', | ||||
|             pathParameters: {'name': currentPublisher.value!.name}, | ||||
|           ) | ||||
|           .then((value) async { | ||||
|             if (value == null) return; | ||||
|             final data = await ref.refresh(publishersManagedProvider.future); | ||||
|             currentPublisher.value = | ||||
|                 data | ||||
|                     .where((e) => e.id == currentPublisher.value!.id) | ||||
|                     .firstOrNull; | ||||
|           }); | ||||
|     } | ||||
|  | ||||
|     void deletePublisher() { | ||||
| @@ -350,7 +355,12 @@ class CreatorHubScreen extends HookConsumerWidget { | ||||
|                               horizontal: 24, | ||||
|                             ), | ||||
|                             onTap: () { | ||||
|                               context.pushNamed('creatorStickers', pathParameters: {'name': currentPublisher.value!.name}); | ||||
|                               context.pushNamed( | ||||
|                                 'creatorStickers', | ||||
|                                 pathParameters: { | ||||
|                                   'name': currentPublisher.value!.name, | ||||
|                                 }, | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                           ListTile( | ||||
| @@ -362,7 +372,12 @@ class CreatorHubScreen extends HookConsumerWidget { | ||||
|                               horizontal: 24, | ||||
|                             ), | ||||
|                             onTap: () { | ||||
|                               context.pushNamed('creatorPosts', pathParameters: {'name': currentPublisher.value!.name}); | ||||
|                               context.pushNamed( | ||||
|                                 'creatorPosts', | ||||
|                                 pathParameters: { | ||||
|                                   'name': currentPublisher.value!.name, | ||||
|                                 }, | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                           ListTile( | ||||
|   | ||||
| @@ -414,7 +414,7 @@ final publisherInvitesProvider = | ||||
| typedef PublisherInvitesRef = | ||||
|     AutoDisposeFutureProviderRef<List<SnPublisherMember>>; | ||||
| String _$publisherMemberListNotifierHash() => | ||||
|     r'237e8f39c9757a6cbdff817853c697539242ad2a'; | ||||
|     r'b4afd5d591a6f3d29f1b45fb1b6d17cb34f3f11b'; | ||||
|  | ||||
| abstract class _$PublisherMemberListNotifier | ||||
|     extends | ||||
|   | ||||
| @@ -28,13 +28,16 @@ class StickersScreen extends HookConsumerWidget { | ||||
|         actions: [ | ||||
|           IconButton( | ||||
|             onPressed: () { | ||||
|               context.pushNamed('creatorStickerPackNew', queryParameters: {'pubName': pubName}).then(( | ||||
|                 value, | ||||
|               ) { | ||||
|                 if (value != null) { | ||||
|                   ref.invalidate(stickerPacksNotifierProvider(pubName)); | ||||
|                 } | ||||
|               }); | ||||
|               context | ||||
|                   .pushNamed( | ||||
|                     'creatorStickerPackNew', | ||||
|                     queryParameters: {'pubName': pubName}, | ||||
|                   ) | ||||
|                   .then((value) { | ||||
|                     if (value != null) { | ||||
|                       ref.invalidate(stickerPacksNotifierProvider(pubName)); | ||||
|                     } | ||||
|                   }); | ||||
|             }, | ||||
|             icon: const Icon(Symbols.add_circle), | ||||
|           ), | ||||
| @@ -71,7 +74,10 @@ class SliverStickerPacksList extends HookConsumerWidget { | ||||
|                 subtitle: Text(sticker.description), | ||||
|                 trailing: const Icon(Symbols.chevron_right), | ||||
|                 onTap: () { | ||||
|                   context.pushNamed('creatorStickerPackDetail', pathParameters: {'pubName': pubName, 'packId': sticker.id}); | ||||
|                   context.pushNamed( | ||||
|                     'creatorStickerPackDetail', | ||||
|                     pathParameters: {'pubName': pubName, 'packId': sticker.id}, | ||||
|                   ); | ||||
|                 }, | ||||
|               ); | ||||
|             }, | ||||
| @@ -99,7 +105,7 @@ class StickerPacksNotifier extends _$StickerPacksNotifier | ||||
|  | ||||
|     try { | ||||
|       final response = await client.get( | ||||
|         '/stickers', | ||||
|         '/sphere/stickers', | ||||
|         queryParameters: { | ||||
|           'offset': offset, | ||||
|           'take': _pageSize, | ||||
| @@ -129,7 +135,7 @@ class StickerPacksNotifier extends _$StickerPacksNotifier | ||||
| Future<SnStickerPack?> stickerPack(Ref ref, String? packId) async { | ||||
|   if (packId == null) return null; | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   final resp = await apiClient.get('/stickers/$packId'); | ||||
|   final resp = await apiClient.get('/sphere/stickers/$packId'); | ||||
|   return SnStickerPack.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| @@ -175,7 +181,7 @@ class EditStickerPacksScreen extends HookConsumerWidget { | ||||
|         submitting.value = true; | ||||
|         final apiClient = ref.watch(apiClientProvider); | ||||
|         final resp = await apiClient.request( | ||||
|           '/stickers', | ||||
|           '/sphere/stickers', | ||||
|           data: { | ||||
|             'name': nameController.text, | ||||
|             'description': descriptionController.text, | ||||
|   | ||||
| @@ -6,7 +6,7 @@ part of 'stickers.dart'; | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$stickerPackHash() => r'4f70d26e695ba1d8c7273d12730f77da79361733'; | ||||
| String _$stickerPackHash() => r'71ef84471237c8191918095094bdfc87d3920e77'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
| @@ -148,7 +148,7 @@ class _StickerPackProviderElement | ||||
| } | ||||
|  | ||||
| String _$stickerPacksNotifierHash() => | ||||
|     r'dc0cc4ec27fdd6d5da28f982ff10c852f8107a18'; | ||||
|     r'0a8edcf9c35396c411f1214f5e77b1e8fac6a3e6'; | ||||
|  | ||||
| abstract class _$StickerPacksNotifier | ||||
|     extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnStickerPack>> { | ||||
|   | ||||
| @@ -25,14 +25,14 @@ part 'hub.g.dart'; | ||||
| Future<DeveloperStats?> developerStats(Ref ref, String? uname) async { | ||||
|   if (uname == null) return null; | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   final resp = await apiClient.get('/developers/$uname/stats'); | ||||
|   final resp = await apiClient.get('/sphere/developers/$uname/stats'); | ||||
|   return DeveloperStats.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| @riverpod | ||||
| Future<List<SnPublisher>> developers(Ref ref) async { | ||||
|   final client = ref.watch(apiClientProvider); | ||||
|   final resp = await client.get('/developers'); | ||||
|   final resp = await client.get('/sphere/developers'); | ||||
|   return resp.data | ||||
|       .map((e) => SnPublisher.fromJson(e)) | ||||
|       .cast<SnPublisher>() | ||||
| @@ -243,7 +243,12 @@ class DeveloperHubScreen extends HookConsumerWidget { | ||||
|                               horizontal: 24, | ||||
|                             ), | ||||
|                             onTap: () { | ||||
|                               context.pushNamed('developerApps', pathParameters: {'name': currentDeveloper.value!.name}); | ||||
|                               context.pushNamed( | ||||
|                                 'developerApps', | ||||
|                                 pathParameters: { | ||||
|                                   'name': currentDeveloper.value!.name, | ||||
|                                 }, | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                         ], | ||||
| @@ -334,7 +339,7 @@ class _DeveloperEnrollmentSheet extends HookConsumerWidget { | ||||
|     Future<void> enroll(SnPublisher publisher) async { | ||||
|       try { | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post('/developers/${publisher.name}/enroll'); | ||||
|         await client.post('/sphere/developers/${publisher.name}/enroll'); | ||||
|         if (context.mounted) { | ||||
|           Navigator.pop(context, true); | ||||
|         } | ||||
|   | ||||
| @@ -6,7 +6,7 @@ part of 'hub.dart'; | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$developerStatsHash() => r'783398cbde09c3d956c3e20b02a1cebd1f8ab748'; | ||||
| String _$developerStatsHash() => r'baa708f3586e8987e221cc8ab825d759658c0f55'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
| @@ -149,7 +149,7 @@ class _DeveloperStatsProviderElement | ||||
|   String? get uname => (origin as DeveloperStatsProvider).uname; | ||||
| } | ||||
|  | ||||
| String _$developersHash() => r'f52639d3c21aafbf235c8ae33f35448baf2989a1'; | ||||
| String _$developersHash() => r'f11335fdf553c661110281edeec70ef89c64727d'; | ||||
|  | ||||
| /// See also [developers]. | ||||
| @ProviderFor(developers) | ||||
|   | ||||
| @@ -39,7 +39,7 @@ class ArticlesListNotifier extends _$ArticlesListNotifier | ||||
|  | ||||
|     try { | ||||
|       final response = await client.get( | ||||
|         '/feeds/articles', | ||||
|         '/sphere/feeds/articles', | ||||
|         queryParameters: queryParams, | ||||
|       ); | ||||
|  | ||||
|   | ||||
| @@ -82,7 +82,7 @@ class NotificationListNotifier extends _$NotificationListNotifier | ||||
|     final queryParams = {'offset': offset, 'take': _pageSize}; | ||||
|  | ||||
|     final response = await client.get( | ||||
|       '/notifications', | ||||
|       '/pusher/notifications', | ||||
|       queryParameters: queryParams, | ||||
|     ); | ||||
|     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||
|   | ||||
| @@ -28,7 +28,7 @@ final notificationUnreadCountNotifierProvider = | ||||
|  | ||||
| typedef _$NotificationUnreadCountNotifier = AutoDisposeAsyncNotifier<int>; | ||||
| String _$notificationListNotifierHash() => | ||||
|     r'934a47bc2ce9e75699a4f53e2169470fd0c04a53'; | ||||
|     r'5099466db475bbcf1ab6b514eb072f1dc4c6f930'; | ||||
|  | ||||
| /// See also [NotificationListNotifier]. | ||||
| @ProviderFor(NotificationListNotifier) | ||||
|   | ||||
| @@ -50,7 +50,7 @@ class PostSearchNotifier | ||||
|       final offset = cursor == null ? 0 : int.parse(cursor); | ||||
|  | ||||
|       final response = await client.get( | ||||
|         '/posts/search', | ||||
|         '/sphere/posts/search', | ||||
|         queryParameters: { | ||||
|           'query': _currentQuery, | ||||
|           'offset': offset, | ||||
|   | ||||
| @@ -28,7 +28,7 @@ part 'pub_profile.g.dart'; | ||||
| @riverpod | ||||
| Future<SnPublisher> publisher(Ref ref, String uname) async { | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   final resp = await apiClient.get("/publishers/$uname"); | ||||
|   final resp = await apiClient.get("/sphere/publishers/$uname"); | ||||
|   return SnPublisher.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| @@ -37,7 +37,7 @@ Future<List<SnAccountBadge>> publisherBadges(Ref ref, String pubName) async { | ||||
|   final pub = await ref.watch(publisherProvider(pubName).future); | ||||
|   if (pub.type != 0 || pub.account == null) return []; | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   final resp = await apiClient.get("/accounts/${pub.account!.name}/badges"); | ||||
|   final resp = await apiClient.get("/id/accounts/${pub.account!.name}/badges"); | ||||
|   return List<SnAccountBadge>.from( | ||||
|     resp.data.map((x) => SnAccountBadge.fromJson(x)), | ||||
|   ); | ||||
| @@ -49,7 +49,7 @@ Future<SnSubscriptionStatus> publisherSubscriptionStatus( | ||||
|   String pubName, | ||||
| ) async { | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   final resp = await apiClient.get("/publishers/$pubName/subscription"); | ||||
|   final resp = await apiClient.get("/sphere/publishers/$pubName/subscription"); | ||||
|   return SnSubscriptionStatus.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| @@ -188,7 +188,10 @@ class PublisherProfileScreen extends HookConsumerWidget { | ||||
|                         onTap: () { | ||||
|                           Navigator.pop(context, true); | ||||
|                           if (data.account?.name != null) { | ||||
|                             context.pushNamed('accountProfile', pathParameters: {'name': data.account!.name}); | ||||
|                             context.pushNamed( | ||||
|                               'accountProfile', | ||||
|                               pathParameters: {'name': data.account!.name}, | ||||
|                             ); | ||||
|                           } | ||||
|                         }, | ||||
|                       ), | ||||
|   | ||||
| @@ -166,7 +166,7 @@ class RealmDetailScreen extends HookConsumerWidget { | ||||
|                                           apiClientProvider, | ||||
|                                         ); | ||||
|                                         await apiClient.post( | ||||
|                                           '/realms/$slug/members/me', | ||||
|                                           '/sphere/realms/$slug/members/me', | ||||
|                                         ); | ||||
|                                         ref.invalidate( | ||||
|                                           realmIdentityProvider(slug), | ||||
| @@ -213,7 +213,10 @@ class RealmDetailScreen extends HookConsumerWidget { | ||||
|                             return ChatRoomListTile( | ||||
|                               room: rooms[index], | ||||
|                               onTap: () { | ||||
|                                 context.pushNamed('chatRoom', pathParameters: {'id': rooms[index].id}); | ||||
|                                 context.pushNamed( | ||||
|                                   'chatRoom', | ||||
|                                   pathParameters: {'id': rooms[index].id}, | ||||
|                                 ); | ||||
|                               }, | ||||
|                             ); | ||||
|                           }, childCount: rooms.length), | ||||
| @@ -251,7 +254,10 @@ class _RealmActionMenu extends HookConsumerWidget { | ||||
|             if (isModerator) | ||||
|               PopupMenuItem( | ||||
|                 onTap: () { | ||||
|                   context.pushReplacement('/sphere/realms/$realmSlug/edit'); | ||||
|                   context.pushReplacementNamed( | ||||
|                     'realmEdit', | ||||
|                     pathParameters: {'slug': realmSlug}, | ||||
|                   ); | ||||
|                 }, | ||||
|                 child: Row( | ||||
|                   children: [ | ||||
| @@ -319,7 +325,7 @@ class _RealmActionMenu extends HookConsumerWidget { | ||||
|                                 if (confirm) { | ||||
|                                   final client = ref.watch(apiClientProvider); | ||||
|                                   client.delete( | ||||
|                                     '/realms/$realmSlug/members/me', | ||||
|                                     '/sphere/realms/$realmSlug/members/me', | ||||
|                                   ); | ||||
|                                   ref.invalidate(realmsJoinedProvider); | ||||
|                                   if (context.mounted) { | ||||
| @@ -389,7 +395,7 @@ class RealmMemberListNotifier extends _$RealmMemberListNotifier | ||||
|     final offset = cursor != null ? int.parse(cursor) : 0; | ||||
|  | ||||
|     final response = await apiClient.get( | ||||
|       '/realms/$realmSlug/members', | ||||
|       '/sphere/realms/$realmSlug/members', | ||||
|       queryParameters: {'offset': offset, 'take': _pageSize}, | ||||
|     ); | ||||
|  | ||||
| @@ -432,7 +438,7 @@ class RealmMemberNotifier extends StateNotifier<RealmMemberState> { | ||||
|  | ||||
|     try { | ||||
|       final response = await _apiClient.get( | ||||
|         '/realms/$realmSlug/members', | ||||
|         '/sphere/realms/$realmSlug/members', | ||||
|         queryParameters: {'offset': offset, 'take': take}, | ||||
|       ); | ||||
|  | ||||
| @@ -487,7 +493,7 @@ class _RealmMemberListSheet extends HookConsumerWidget { | ||||
|       try { | ||||
|         final apiClient = ref.watch(apiClientProvider); | ||||
|         await apiClient.post( | ||||
|           '/realms/invites/$realmSlug', | ||||
|           '/sphere/realms/invites/$realmSlug', | ||||
|           data: {'related_user_id': result.id, 'role': 0}, | ||||
|         ); | ||||
|         // Refresh both providers | ||||
| @@ -619,7 +625,7 @@ class _RealmMemberListSheet extends HookConsumerWidget { | ||||
|                                       apiClientProvider, | ||||
|                                     ); | ||||
|                                     await apiClient.delete( | ||||
|                                       '/realms/$realmSlug/members/${member.accountId}', | ||||
|                                       '/sphere/realms/$realmSlug/members/${member.accountId}', | ||||
|                                     ); | ||||
|                                     // Refresh both providers | ||||
|                                     memberNotifier.reset(); | ||||
| @@ -769,7 +775,7 @@ class _RealmMemberRoleSheet extends HookConsumerWidget { | ||||
|  | ||||
|                       final apiClient = ref.read(apiClientProvider); | ||||
|                       await apiClient.patch( | ||||
|                         '/realms/$realmSlug/members/${member.accountId}/role', | ||||
|                         '/sphere/realms/$realmSlug/members/${member.accountId}/role', | ||||
|                         data: newRole, | ||||
|                       ); | ||||
|  | ||||
|   | ||||
| @@ -399,7 +399,7 @@ class _RealmChatRoomsProviderElement | ||||
| } | ||||
|  | ||||
| String _$realmMemberListNotifierHash() => | ||||
|     r'b2e3eefc62a597f45df9470b2058fdda62f8853f'; | ||||
|     r'022bcef5a90cbae05ff23b937851afc3ef913d42'; | ||||
|  | ||||
| abstract class _$RealmMemberListNotifier | ||||
|     extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnRealmMember>> { | ||||
|   | ||||
| @@ -41,7 +41,6 @@ class RealmListScreen extends HookConsumerWidget { | ||||
|     final realmInvites = ref.watch(realmInvitesProvider); | ||||
|  | ||||
|     return AppScaffold( | ||||
|       extendBody: false, // Prevent conflicts with tabs navigation | ||||
|       noBackground: false, | ||||
|       appBar: AppBar( | ||||
|         title: const Text('realms').tr(), | ||||
| @@ -70,6 +69,7 @@ class RealmListScreen extends HookConsumerWidget { | ||||
|               showModalBottomSheet( | ||||
|                 context: context, | ||||
|                 isScrollControlled: true, | ||||
|                 useRootNavigator: true, | ||||
|                 builder: (_) => const _RealmInviteSheet(), | ||||
|               ); | ||||
|             }, | ||||
| @@ -108,7 +108,10 @@ class RealmListScreen extends HookConsumerWidget { | ||||
|                           title: Text(value[item].name), | ||||
|                           subtitle: Text(value[item].description), | ||||
|                           onTap: () { | ||||
|                             context.pushNamed('realmDetail', pathParameters: {'slug': value[item].slug}); | ||||
|                             context.pushNamed( | ||||
|                               'realmDetail', | ||||
|                               pathParameters: {'slug': value[item].slug}, | ||||
|                             ); | ||||
|                           }, | ||||
|                           contentPadding: const EdgeInsets.only( | ||||
|                             left: 16, | ||||
| @@ -253,7 +256,7 @@ class EditRealmScreen extends HookConsumerWidget { | ||||
|       try { | ||||
|         final client = ref.watch(apiClientProvider); | ||||
|         final resp = await client.request( | ||||
|           slug == null ? '/realms' : '/realms/$slug', | ||||
|           '/sphere${slug == null ? '/realms' : '/realms/$slug'}', | ||||
|           data: { | ||||
|             'slug': slugController.text, | ||||
|             'name': nameController.text, | ||||
| @@ -276,128 +279,131 @@ class EditRealmScreen extends HookConsumerWidget { | ||||
|     } | ||||
|  | ||||
|     return AppScaffold( | ||||
|       noBackground: false, | ||||
|       appBar: AppBar( | ||||
|         title: Text(slug == null ? 'createRealm'.tr() : 'editRealm'.tr()), | ||||
|         leading: const PageBackButton(), | ||||
|       ), | ||||
|       body: Column( | ||||
|         children: [ | ||||
|           AspectRatio( | ||||
|             aspectRatio: 16 / 7, | ||||
|             child: Stack( | ||||
|               clipBehavior: Clip.none, | ||||
|               fit: StackFit.expand, | ||||
|               children: [ | ||||
|                 GestureDetector( | ||||
|                   child: Container( | ||||
|                     color: Theme.of(context).colorScheme.surfaceContainerHigh, | ||||
|                     child: | ||||
|                         background.value != null | ||||
|                             ? CloudFileWidget( | ||||
|                               item: background.value!, | ||||
|                               fit: BoxFit.cover, | ||||
|                             ) | ||||
|                             : const SizedBox.shrink(), | ||||
|                   ), | ||||
|                   onTap: () { | ||||
|                     setPicture('background'); | ||||
|                   }, | ||||
|                 ), | ||||
|                 Positioned( | ||||
|                   left: 20, | ||||
|                   bottom: -32, | ||||
|                   child: GestureDetector( | ||||
|                     child: ProfilePictureWidget( | ||||
|                       fileId: picture.value?.id, | ||||
|                       radius: 40, | ||||
|                       fallbackIcon: Symbols.group, | ||||
|       body: SingleChildScrollView( | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             AspectRatio( | ||||
|               aspectRatio: 16 / 7, | ||||
|               child: Stack( | ||||
|                 clipBehavior: Clip.none, | ||||
|                 fit: StackFit.expand, | ||||
|                 children: [ | ||||
|                   GestureDetector( | ||||
|                     child: Container( | ||||
|                       color: Theme.of(context).colorScheme.surfaceContainerHigh, | ||||
|                       child: | ||||
|                           background.value != null | ||||
|                               ? CloudFileWidget( | ||||
|                                 item: background.value!, | ||||
|                                 fit: BoxFit.cover, | ||||
|                               ) | ||||
|                               : const SizedBox.shrink(), | ||||
|                     ), | ||||
|                     onTap: () { | ||||
|                       setPicture('picture'); | ||||
|                       setPicture('background'); | ||||
|                     }, | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|                   Positioned( | ||||
|                     left: 20, | ||||
|                     bottom: -32, | ||||
|                     child: GestureDetector( | ||||
|                       child: ProfilePictureWidget( | ||||
|                         fileId: picture.value?.id, | ||||
|                         radius: 40, | ||||
|                         fallbackIcon: Symbols.group, | ||||
|                       ), | ||||
|                       onTap: () { | ||||
|                         setPicture('picture'); | ||||
|                       }, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ).padding(bottom: 32), | ||||
|             Form( | ||||
|               key: formKey, | ||||
|               child: Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 children: [ | ||||
|                   TextFormField( | ||||
|                     controller: slugController, | ||||
|                     decoration: InputDecoration( | ||||
|                       labelText: 'slug'.tr(), | ||||
|                       helperText: 'slugHint'.tr(), | ||||
|                     ), | ||||
|                     onTapOutside: | ||||
|                         (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                   ), | ||||
|                   const SizedBox(height: 16), | ||||
|                   TextFormField( | ||||
|                     controller: nameController, | ||||
|                     decoration: InputDecoration(labelText: 'name'.tr()), | ||||
|                     onTapOutside: | ||||
|                         (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                   ), | ||||
|                   const SizedBox(height: 16), | ||||
|                   TextFormField( | ||||
|                     controller: descriptionController, | ||||
|                     decoration: InputDecoration( | ||||
|                       labelText: 'description'.tr(), | ||||
|                       alignLabelWithHint: true, | ||||
|                     ), | ||||
|                     minLines: 3, | ||||
|                     maxLines: null, | ||||
|                     onTapOutside: | ||||
|                         (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                   ), | ||||
|                   const SizedBox(height: 16), | ||||
|                   Card( | ||||
|                     margin: EdgeInsets.zero, | ||||
|                     child: Column( | ||||
|                       children: [ | ||||
|                         CheckboxListTile( | ||||
|                           secondary: const Icon(Symbols.public), | ||||
|                           title: Text('publicRealm').tr(), | ||||
|                           subtitle: Text('publicRealmDescription').tr(), | ||||
|                           value: isPublic.value, | ||||
|                           onChanged: (value) { | ||||
|                             isPublic.value = value ?? true; | ||||
|                           }, | ||||
|                           shape: RoundedRectangleBorder( | ||||
|                             borderRadius: BorderRadius.circular(8), | ||||
|                           ), | ||||
|                         ), | ||||
|                         CheckboxListTile( | ||||
|                           secondary: const Icon(Symbols.travel_explore), | ||||
|                           title: Text('communityRealm').tr(), | ||||
|                           subtitle: Text('communityRealmDescription').tr(), | ||||
|                           value: isCommunity.value, | ||||
|                           onChanged: (value) { | ||||
|                             isCommunity.value = value ?? false; | ||||
|                           }, | ||||
|                           shape: RoundedRectangleBorder( | ||||
|                             borderRadius: BorderRadius.circular(8), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ], | ||||
|                     ), | ||||
|                   ), | ||||
|                   const SizedBox(height: 16), | ||||
|                   Align( | ||||
|                     alignment: Alignment.centerRight, | ||||
|                     child: TextButton.icon( | ||||
|                       onPressed: submitting.value ? null : performAction, | ||||
|                       label: Text('saveChanges'.tr()), | ||||
|                       icon: const Icon(Symbols.save), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ).padding(all: 24), | ||||
|             ), | ||||
|           ).padding(bottom: 32), | ||||
|           Form( | ||||
|             key: formKey, | ||||
|             child: Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 TextFormField( | ||||
|                   controller: slugController, | ||||
|                   decoration: InputDecoration( | ||||
|                     labelText: 'slug'.tr(), | ||||
|                     helperText: 'slugHint'.tr(), | ||||
|                   ), | ||||
|                   onTapOutside: | ||||
|                       (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 TextFormField( | ||||
|                   controller: nameController, | ||||
|                   decoration: InputDecoration(labelText: 'name'.tr()), | ||||
|                   onTapOutside: | ||||
|                       (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 TextFormField( | ||||
|                   controller: descriptionController, | ||||
|                   decoration: InputDecoration( | ||||
|                     labelText: 'description'.tr(), | ||||
|                     alignLabelWithHint: true, | ||||
|                   ), | ||||
|                   minLines: 3, | ||||
|                   maxLines: null, | ||||
|                   onTapOutside: | ||||
|                       (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 Card( | ||||
|                   margin: EdgeInsets.zero, | ||||
|                   child: Column( | ||||
|                     children: [ | ||||
|                       CheckboxListTile( | ||||
|                         secondary: const Icon(Symbols.public), | ||||
|                         title: Text('publicRealm').tr(), | ||||
|                         subtitle: Text('publicRealmDescription').tr(), | ||||
|                         value: isPublic.value, | ||||
|                         onChanged: (value) { | ||||
|                           isPublic.value = value ?? true; | ||||
|                         }, | ||||
|                         shape: RoundedRectangleBorder( | ||||
|                           borderRadius: BorderRadius.circular(8), | ||||
|                         ), | ||||
|                       ), | ||||
|                       CheckboxListTile( | ||||
|                         secondary: const Icon(Symbols.travel_explore), | ||||
|                         title: Text('communityRealm').tr(), | ||||
|                         subtitle: Text('communityRealmDescription').tr(), | ||||
|                         value: isCommunity.value, | ||||
|                         onChanged: (value) { | ||||
|                           isCommunity.value = value ?? false; | ||||
|                         }, | ||||
|                         shape: RoundedRectangleBorder( | ||||
|                           borderRadius: BorderRadius.circular(8), | ||||
|                         ), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 Align( | ||||
|                   alignment: Alignment.centerRight, | ||||
|                   child: TextButton.icon( | ||||
|                     onPressed: submitting.value ? null : performAction, | ||||
|                     label: Text('saveChanges'.tr()), | ||||
|                     icon: const Icon(Symbols.save), | ||||
|                   ), | ||||
|                 ), | ||||
|               ], | ||||
|             ).padding(all: 24), | ||||
|           ), | ||||
|         ], | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -55,9 +55,9 @@ class TabsScreen extends HookConsumerWidget { | ||||
|     final routes = ['/', '/chat', '/realms', '/account']; | ||||
|  | ||||
|     int getCurrentIndex() { | ||||
|       if (currentLocation.startsWith('/sphere/chat')) return 1; | ||||
|       if (currentLocation.startsWith('/sphere/realms')) return 2; | ||||
|       if (currentLocation.startsWith('/id/account')) return 3; | ||||
|       if (currentLocation.startsWith('/chat')) return 1; | ||||
|       if (currentLocation.startsWith('/realms')) return 2; | ||||
|       if (currentLocation.startsWith('/account')) return 3; | ||||
|       return 0; // Default to explore | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -51,7 +51,7 @@ class TransactionListNotifier extends _$TransactionListNotifier | ||||
|     final queryParams = {'offset': offset, 'take': _pageSize}; | ||||
|  | ||||
|     final response = await client.get( | ||||
|       '/wallets/transactions', | ||||
|       '/id/wallets/transactions', | ||||
|       queryParameters: queryParams, | ||||
|     ); | ||||
|     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||
| @@ -110,7 +110,7 @@ class WalletScreen extends HookConsumerWidget { | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ); | ||||
|             ).center(); | ||||
|           } | ||||
|  | ||||
|           return Column( | ||||
|   | ||||
| @@ -25,7 +25,7 @@ final walletCurrentProvider = AutoDisposeFutureProvider<SnWallet?>.internal( | ||||
| // ignore: unused_element | ||||
| typedef WalletCurrentRef = AutoDisposeFutureProviderRef<SnWallet?>; | ||||
| String _$transactionListNotifierHash() => | ||||
|     r'148ffb0ee9e3be3b92de432f314d8ee2f09e9a24'; | ||||
|     r'7b777cd44f3351f68f7bd1dd76bfe8b388381bdb'; | ||||
|  | ||||
| /// See also [TransactionListNotifier]. | ||||
| @ProviderFor(TransactionListNotifier) | ||||
|   | ||||
| @@ -11,13 +11,16 @@ class AbuseReportService { | ||||
|   AbuseReportService(this.ref); | ||||
|  | ||||
|   Future<SnAbuseReport> getReport(String id) async { | ||||
|     final response = | ||||
|         await ref.read(apiClientProvider).get('/safety/reports/me/$id'); | ||||
|     final response = await ref | ||||
|         .read(apiClientProvider) | ||||
|         .get('/id/safety/reports/me/$id'); | ||||
|     return SnAbuseReport.fromJson(response.data); | ||||
|   } | ||||
|  | ||||
|   Future<List<SnAbuseReport>> getReports() async { | ||||
|     final response = await ref.read(apiClientProvider).get('/safety/reports/me'); | ||||
|     final response = await ref | ||||
|         .read(apiClientProvider) | ||||
|         .get('/id/safety/reports/me'); | ||||
|     return (response.data as List) | ||||
|         .map((json) => SnAbuseReport.fromJson(json)) | ||||
|         .toList(); | ||||
|   | ||||
| @@ -67,7 +67,8 @@ class FortuneGraphWidget extends HookConsumerWidget { | ||||
|                 constraints: const BoxConstraints(), | ||||
|                 onPressed: () { | ||||
|                   context.pushNamed( | ||||
|                     '/account/$eventCalanderUser/calendar', | ||||
|                     'accountCalendar', | ||||
|                     pathParameters: {'name': eventCalanderUser!}, | ||||
|                   ); | ||||
|                 }, | ||||
|               ), | ||||
|   | ||||
| @@ -38,7 +38,8 @@ class CloudFileList extends HookConsumerWidget { | ||||
|   double calculateAspectRatio() { | ||||
|     double total = 0; | ||||
|     for (var ratio in files.map((e) => e.fileMeta?['ratio'] ?? 1)) { | ||||
|       total += double.parse(ratio); | ||||
|       if (ratio is double) total += ratio; | ||||
|       if (ratio is String) total += double.parse(ratio); | ||||
|     } | ||||
|     if (total == 0) return 1; | ||||
|     return total / files.length; | ||||
| @@ -78,6 +79,7 @@ class CloudFileList extends HookConsumerWidget { | ||||
|                 if (!disableZoomIn) { | ||||
|                   context.pushTransparentRoute( | ||||
|                     CloudFileZoomIn(item: files.first, heroTag: heroTags.first), | ||||
|                     rootNavigator: true, | ||||
|                   ); | ||||
|                 } | ||||
|               }, | ||||
| @@ -505,7 +507,7 @@ class _CloudFileListEntry extends StatelessWidget { | ||||
|         if (isImage) | ||||
|           Positioned.fill( | ||||
|             child: | ||||
|                 file.fileMeta?['blur'] != null | ||||
|                 file.fileMeta?['blur'] is String | ||||
|                     ? BlurHash(hash: file.fileMeta?['blur']) | ||||
|                     : ImageFiltered( | ||||
|                       imageFilter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), | ||||
|   | ||||
| @@ -27,7 +27,12 @@ class CloudFileWidget extends ConsumerWidget { | ||||
|     final serverUrl = ref.watch(serverUrlProvider); | ||||
|     final uri = '$serverUrl/drive/files/${item.id}'; | ||||
|  | ||||
|     var ratio = double.parse(item.fileMeta?['ratio'] ?? 1); | ||||
|     var ratio = | ||||
|         item.fileMeta?['ratio'] is num | ||||
|             ? item.fileMeta!['ratio'].toDouble() | ||||
|             : item.fileMeta?['ratio'] is String | ||||
|             ? double.parse(item.fileMeta!['ratio']) | ||||
|             : 1.0; | ||||
|     if (ratio == 0) ratio = 1.0; | ||||
|     final content = switch (item.mimeType?.split('/').firstOrNull) { | ||||
|       "image" => AspectRatio( | ||||
|   | ||||
| @@ -72,7 +72,10 @@ class PostItem extends HookConsumerWidget { | ||||
|           children: [ | ||||
|             GestureDetector( | ||||
|               onTap: () { | ||||
|                 context.pushNamed('publisherProfile', pathParameters: {'name': item.publisher.name}); | ||||
|                 context.pushNamed( | ||||
|                   'publisherProfile', | ||||
|                   pathParameters: {'name': item.publisher.name}, | ||||
|                 ); | ||||
|               }, | ||||
|               child: Row( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.center, | ||||
| @@ -254,7 +257,10 @@ class PostItem extends HookConsumerWidget { | ||||
|                 GestureDetector( | ||||
|                   child: ProfilePictureWidget(file: item.publisher.picture), | ||||
|                   onTap: () { | ||||
|                     context.pushNamed('publisherProfile', pathParameters: {'name': item.publisher.name}); | ||||
|                     context.pushNamed( | ||||
|                       'publisherProfile', | ||||
|                       pathParameters: {'name': item.publisher.name}, | ||||
|                     ); | ||||
|                   }, | ||||
|                 ), | ||||
|                 Expanded( | ||||
| @@ -427,7 +433,10 @@ class PostItem extends HookConsumerWidget { | ||||
|                     ), | ||||
|                     onTap: () { | ||||
|                       if (isOpenable) { | ||||
|                         context.pushNamed('postDetail', pathParameters: {'id': item.id}); | ||||
|                         context.pushNamed( | ||||
|                           'postDetail', | ||||
|                           pathParameters: {'id': item.id}, | ||||
|                         ); | ||||
|                       } | ||||
|                     }, | ||||
|                   ), | ||||
| @@ -496,11 +505,13 @@ class PostItem extends HookConsumerWidget { | ||||
|                 title: 'edit'.tr(), | ||||
|                 image: MenuImage.icon(Symbols.edit), | ||||
|                 callback: () { | ||||
|                   context.pushNamed('postEdit', pathParameters: {'id': item.id}).then((value) { | ||||
|                     if (value != null) { | ||||
|                       onRefresh?.call(); | ||||
|                     } | ||||
|                   }); | ||||
|                   context | ||||
|                       .pushNamed('postEdit', pathParameters: {'id': item.id}) | ||||
|                       .then((value) { | ||||
|                         if (value != null) { | ||||
|                           onRefresh?.call(); | ||||
|                         } | ||||
|                       }); | ||||
|                 }, | ||||
|               ), | ||||
|             if (isAuthor) | ||||
| @@ -732,7 +743,13 @@ Widget _buildReferencePost(BuildContext context, SnPost item) { | ||||
|         ), | ||||
|       ], | ||||
|     ), | ||||
|   ).gestures(onTap: () => context.pushNamed('postDetail', pathParameters: {'id': referencePost.id})); | ||||
|   ).gestures( | ||||
|     onTap: | ||||
|         () => context.pushNamed( | ||||
|           'postDetail', | ||||
|           pathParameters: {'id': referencePost.id}, | ||||
|         ), | ||||
|   ); | ||||
| } | ||||
|  | ||||
| class PostReactionList extends HookConsumerWidget { | ||||
| @@ -757,7 +774,7 @@ class PostReactionList extends HookConsumerWidget { | ||||
|       submitting.value = true; | ||||
|       await client | ||||
|           .post( | ||||
|             '/posts/$parentId/reactions', | ||||
|             '/sphere/posts/$parentId/reactions', | ||||
|             data: {'symbol': symbol, 'attitude': attitude}, | ||||
|           ) | ||||
|           .catchError((err) { | ||||
|   | ||||
| @@ -43,7 +43,7 @@ class PostQuickReply extends HookConsumerWidget { | ||||
|       try { | ||||
|         final client = ref.watch(apiClientProvider); | ||||
|         await client.post( | ||||
|           '/posts', | ||||
|           '/sphere/posts', | ||||
|           data: { | ||||
|             'content': contentController.text, | ||||
|             'replied_post_id': parent.id, | ||||
|   | ||||
| @@ -35,7 +35,7 @@ class PostRepliesNotifier extends _$PostRepliesNotifier | ||||
|     final offset = cursor == null ? 0 : int.parse(cursor); | ||||
|  | ||||
|     final response = await client.get( | ||||
|       '/posts/$_postId/replies', | ||||
|       '/sphere/posts/$_postId/replies', | ||||
|       queryParameters: {'offset': offset, 'take': _pageSize}, | ||||
|     ); | ||||
|  | ||||
| @@ -57,7 +57,11 @@ class PostRepliesNotifier extends _$PostRepliesNotifier | ||||
| class PostRepliesList extends HookConsumerWidget { | ||||
|   final String postId; | ||||
|   final Color? backgroundColor; | ||||
|   const PostRepliesList({super.key, required this.postId, this.backgroundColor}); | ||||
|   const PostRepliesList({ | ||||
|     super.key, | ||||
|     required this.postId, | ||||
|     this.backgroundColor, | ||||
|   }); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
| @@ -93,7 +97,8 @@ class PostRepliesList extends HookConsumerWidget { | ||||
|               children: [ | ||||
|                 PostItem( | ||||
|                   item: data.items[index], | ||||
|                   backgroundColor: backgroundColor ?? (isWide ? Colors.transparent : null), | ||||
|                   backgroundColor: | ||||
|                       backgroundColor ?? (isWide ? Colors.transparent : null), | ||||
|                   showReferencePost: false, | ||||
|                 ), | ||||
|                 const Divider(height: 1), | ||||
|   | ||||
| @@ -7,7 +7,7 @@ part of 'post_replies.dart'; | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$postRepliesNotifierHash() => | ||||
|     r'49c178102ec0a4136974a0e9a8f090f511abd542'; | ||||
|     r'1cdda919249e3bf34459369e033ad5de8dbcf3f8'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
|   | ||||
| @@ -34,7 +34,7 @@ class RealmListNotifier extends _$RealmListNotifier | ||||
|     }; | ||||
|  | ||||
|     final response = await client.get( | ||||
|       '/discovery/realms', | ||||
|       '/sphere/discovery/realms', | ||||
|       queryParameters: queryParams, | ||||
|     ); | ||||
|     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ part of 'realm_list.dart'; | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$realmListNotifierHash() => r'02dee373a5609a5617b04ffec395d09dea7ae070'; | ||||
| String _$realmListNotifierHash() => r'8ae5c3ae2837acae4c7bf5e44578518afc9ea1a6'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
|   | ||||
| @@ -43,7 +43,7 @@ class AbuseReportSheet extends HookConsumerWidget { | ||||
|       try { | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post( | ||||
|           '/safety/reports', | ||||
|           '/id/safety/reports', | ||||
|           data: { | ||||
|             'resource_identifier': resourceIdentifier, | ||||
|             'type': selectedType.value, | ||||
|   | ||||
| @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev | ||||
| # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html | ||||
| # In Windows, build-name is used as the major, minor, and patch parts | ||||
| # of the product and file versions while build-number is used as the build suffix. | ||||
| version: 3.1.0+113 | ||||
| version: 3.1.0+114 | ||||
|  | ||||
| environment: | ||||
|   sdk: ^3.7.2 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user