Compare commits
	
		
			7 Commits
		
	
	
		
			3.0.0+108
			...
			356b7bf01a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 356b7bf01a | |||
| 450d5ebc81 | |||
| f04285848f | |||
| c4becb0a05 | |||
| d22619396b | |||
| fe8640a6db | |||
| ff475d43dd | 
							
								
								
									
										5
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ name: Build Release | ||||
| on: | ||||
|   push: | ||||
|     tags: | ||||
|       - '*' | ||||
|       - "*" | ||||
|   workflow_dispatch: | ||||
|  | ||||
| jobs: | ||||
| @@ -59,6 +59,7 @@ jobs: | ||||
|           sudo apt-get install -y libnotify-dev | ||||
|           sudo apt-get install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev | ||||
|           sudo apt-get install -y gstreamer-1.0 | ||||
|           sudo apt-get install -y libsecret-1-0 | ||||
|       - run: flutter pub get | ||||
|       - run: flutter build linux | ||||
|       - name: Archive production artifacts | ||||
| @@ -80,4 +81,4 @@ jobs: | ||||
|         uses: actions/upload-artifact@v4 | ||||
|         with: | ||||
|           name: build-output-linux-appimage | ||||
|           path: './*.AppImage*' | ||||
|           path: "./*.AppImage*" | ||||
|   | ||||
| @@ -98,7 +98,7 @@ | ||||
|         <receiver | ||||
|             android:name=".receiver.ReplyReceiver" | ||||
|             android:enabled="true" | ||||
|             android:exported="false" /> | ||||
|             android:exported="true" /> | ||||
|  | ||||
|         <service | ||||
|             android:name=".service.MessagingService" | ||||
|   | ||||
| @@ -1,14 +1,39 @@ | ||||
| package dev.solsynth.solian | ||||
|  | ||||
| import android.content.Intent | ||||
| import io.flutter.embedding.android.FlutterActivity | ||||
| import io.flutter.embedding.engine.FlutterEngine | ||||
| import io.flutter.plugin.common.MethodChannel | ||||
| import io.flutter.plugins.sharedpreferences.LegacySharedPreferencesPlugin | ||||
|  | ||||
| class MainActivity : FlutterActivity() | ||||
| { | ||||
|     private val CHANNEL = "dev.solsynth.solian/notifications" | ||||
|  | ||||
|     override fun configureFlutterEngine(flutterEngine: FlutterEngine) { | ||||
|         super.configureFlutterEngine(flutterEngine) | ||||
|         // https://github.com/flutter/flutter/issues/153075#issuecomment-2693189362 | ||||
|         flutterEngine.plugins.add(LegacySharedPreferencesPlugin()) | ||||
|  | ||||
|         MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> | ||||
|             if (call.method == "initialLink") { | ||||
|                 val roomId = intent.getStringExtra("room_id") | ||||
|                 if (roomId != null) { | ||||
|                     result.success("/rooms/$roomId") | ||||
|                 } else { | ||||
|                     result.success(null) | ||||
|                 } | ||||
|             } else { | ||||
|                 result.notImplemented() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onNewIntent(intent: Intent) { | ||||
|         super.onNewIntent(intent) | ||||
|         val roomId = intent.getStringExtra("room_id") | ||||
|         if (roomId != null) { | ||||
|             MethodChannel(flutterEngine!!.dartExecutor.binaryMessenger, CHANNEL).invokeMethod("newLink", "/rooms/$roomId") | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,47 +1,46 @@ | ||||
| package dev.solsynth.solian.network | ||||
|  | ||||
| import android.content.Context | ||||
| import okhttp3.* | ||||
| import android.content.SharedPreferences | ||||
| import okhttp3.Call | ||||
| import okhttp3.Callback | ||||
| import okhttp3.MediaType.Companion.toMediaType | ||||
| import okhttp3.OkHttpClient | ||||
| import okhttp3.Request | ||||
| import okhttp3.RequestBody.Companion.toRequestBody | ||||
| import okhttp3.Response | ||||
| import org.json.JSONObject | ||||
| import java.io.IOException | ||||
|  | ||||
| class ApiClient(private val context: Context) { | ||||
|     private val client = OkHttpClient() | ||||
|     private val sharedPreferences: SharedPreferences = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) | ||||
|  | ||||
|     fun sendMessage(roomId: String, content: String, repliedMessageId: String, callback: () -> Unit) { | ||||
|         val prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) | ||||
|         val token = prefs.getString("flutter.token", null) | ||||
|         val serverUrl = prefs.getString("flutter.serverUrl", null) | ||||
|  | ||||
|         if (token == null || serverUrl == null) { | ||||
|     fun sendMessage(roomId: String, message: String, replyTo: String, callback: (Boolean) -> Unit) { | ||||
|         val token = sharedPreferences.getString("flutter.token", null) | ||||
|         if (token == null) { | ||||
|             callback(false) | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         val url = "$serverUrl/chat/$roomId/messages" | ||||
|  | ||||
|         val json = JSONObject() | ||||
|         json.put("content", content) | ||||
|         json.put("replied_message_id", repliedMessageId) | ||||
|  | ||||
|         val requestBody = json.toString().toRequestBody("application/json; charset=utf-8".toMediaType()) | ||||
|  | ||||
|         val json = JSONObject().apply { | ||||
|             put("content", message) | ||||
|             put("reply_to", replyTo) | ||||
|         } | ||||
|         val body = json.toString().toRequestBody("application/json; charset=utf-8".toMediaType()) | ||||
|         val request = Request.Builder() | ||||
|             .url(url) | ||||
|             .post(requestBody) | ||||
|             .addHeader("Authorization", "AtField $token") | ||||
|             .url("https://solian.dev/api/rooms/$roomId/messages") | ||||
|             .header("Authorization", "Bearer $token") | ||||
|             .post(body) | ||||
|             .build() | ||||
|  | ||||
|         client.newCall(request).enqueue(object : Callback { | ||||
|             override fun onFailure(call: Call, e: IOException) { | ||||
|                 // Handle failure | ||||
|                 callback() | ||||
|                 callback(false) | ||||
|             } | ||||
|  | ||||
|             override fun onResponse(call: Call, response: Response) { | ||||
|                 // Handle success | ||||
|                 callback() | ||||
|                 callback(response.isSuccessful) | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|   | ||||
| @@ -72,6 +72,7 @@ class MessagingService: FirebaseMessagingService() { | ||||
|  | ||||
|         val intent = Intent(this, MainActivity::class.java) | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | ||||
|         intent.putExtra("room_id", roomId) | ||||
|         val pendingIntent = PendingIntent.getActivity(this, 0, intent, pendingIntentFlags) | ||||
|  | ||||
|         val notificationBuilder = NotificationCompat.Builder(this, "messages") | ||||
|   | ||||
| @@ -89,14 +89,32 @@ | ||||
|   "authFactorInAppNotifyDescription": "A one-time code sent via in-app notification.", | ||||
|   "authFactorPin": "Pin Code", | ||||
|   "authFactorPinDescription": "It consists of 6 digits. It cannot be used to log in. When performing some dangerous operations, the system will ask you to enter this PIN for confirmation.", | ||||
|   "realms": "Realms", | ||||
|   "createRealm": "Create a Realm", | ||||
|   "createRealmHint": "Meet friends with same interests, build communities, and more.", | ||||
|   "editRealm": "Edit Realm", | ||||
|   "deleteRealm": "Delete Realm", | ||||
|   "deleteRealmHint": "Are you sure to delete this realm? This will also deleted all the channels, publishers, and posts under this realm.", | ||||
|   "explore": "Explore", | ||||
|   "exploreFilterSubscriptions": "Subscriptions", | ||||
|   "exploreFilterFriends": "Friends", | ||||
|   "discover": "Discover", | ||||
|   "joinRealm": "Join Realm", | ||||
|   "account": "Account", | ||||
|   "name": "Name", | ||||
|   "slug": "Slug", | ||||
|   "slugHint": "The slug will be used in the URL to access this resource, it should be unique and URL safe.", | ||||
|   "createChatRoom": "Create a Room", | ||||
|   "editChatRoom": "Edit Room", | ||||
|   "deleteChatRoom": "Delete Room", | ||||
|   "deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.", | ||||
|   "chat": "Chat", | ||||
|   "chatTabAll": "All", | ||||
|   "chatTabDirect": "Direct Messages", | ||||
|   "chatTabGroup": "Group Chats", | ||||
|   "chatMessageHint": "Message in {}", | ||||
|   "chatDirectMessageHint": "Message to {}", | ||||
|   "directMessage": "Direct Message", | ||||
|   "loading": "Loading...", | ||||
|   "descriptionNone": "No description yet.", | ||||
|   "invites": "Invites", | ||||
| @@ -231,6 +249,7 @@ | ||||
|   "uploadingProgress": "Uploading {} of {}", | ||||
|   "uploadAll": "Upload All", | ||||
|   "stickerCopyPlaceholder": "Copy Placeholder", | ||||
|   "realmSelection": "Select a Realm", | ||||
|   "individual": "Individual", | ||||
|   "firstPostBadgeName": "First Post", | ||||
|   "firstPostBadgeDescription": "Created your first post on Solar Network", | ||||
| @@ -286,6 +305,12 @@ | ||||
|   "levelingProgressExperience": "{} EXP", | ||||
|   "levelingProgressLevel": "Level {}", | ||||
|   "fileUploadingProgress": "Uploading file #{}: {}%", | ||||
|   "removeChatMember": "Remove Chat Room Member", | ||||
|   "removeChatMemberHint": "Are you sure to remove this member from the room?", | ||||
|   "removeRealmMember": "Remove Realm Member", | ||||
|   "removeRealmMemberHint": "Are you sure to remove this member from the realm?", | ||||
|   "removePublisherMember": "Remove Publisher Member", | ||||
|   "removePublisherMemberHint": "Are you sure to remove this member from the publisher?", | ||||
|   "memberRole": "Member Role", | ||||
|   "memberRoleHint": "Greater number has higher permission.", | ||||
|   "memberRoleEdit": "Edit role for @{}", | ||||
| @@ -293,6 +318,10 @@ | ||||
|   "openLinkConfirmDescription": "You're going to leave the Solar Network and open the link ({}) in your browser. It is not related to Solar Network. Beware of phishing and scams.", | ||||
|   "brokenLink": "Unable open link {}... It might be broken or missing uri parts...", | ||||
|   "copyToClipboard": "Copy to clipboard", | ||||
|   "leaveChatRoom": "Leave Chat Room", | ||||
|   "leaveChatRoomHint": "Are you sure to leave this chat room?", | ||||
|   "leaveRealm": "Leave Realm", | ||||
|   "leaveRealmHint": "Are you sure to leave this realm?", | ||||
|   "walletNotFound": "Wallet not found", | ||||
|   "walletCreateHint": "You don't have a wallet yet. Create one to start using the Solar Network eWallet.", | ||||
|   "walletCreate": "Create a Wallet", | ||||
| @@ -304,6 +333,12 @@ | ||||
|   "settingsBackgroundImageClear": "Clear Background Image", | ||||
|   "settingsBackgroundGenerateColor": "Generate color scheme from Bacground Image", | ||||
|   "messageNone": "No content to display", | ||||
|   "unreadMessages": { | ||||
|     "one": "{} unread message", | ||||
|     "other": "{} unread messages" | ||||
|   }, | ||||
|   "chatBreakNone": "None", | ||||
|   "settingsRealmCompactView": "Compact Realm View", | ||||
|   "settingsMixedFeed": "Mixed Feed", | ||||
|   "settingsAutoTranslate": "Auto Translate", | ||||
|   "settingsHideBottomNav": "Hide Bottom Navigation", | ||||
| @@ -346,6 +381,7 @@ | ||||
|   "postVisibilityUnlisted": "Unlisted", | ||||
|   "postVisibilityPrivate": "Private", | ||||
|   "postTruncated": "Content truncated, tap to view full post", | ||||
|   "copyMessage": "Copy Message", | ||||
|   "authFactor": "Authentication Factor", | ||||
|   "authFactorDelete": "Delete the Factor", | ||||
|   "authFactorDeleteHint": "Are you sure you want to delete this authentication factor? This action cannot be undone.", | ||||
| @@ -373,6 +409,10 @@ | ||||
|   "lastActiveAt": "Last active at {}", | ||||
|   "authDeviceLogout": "Logout", | ||||
|   "authDeviceLogoutHint": "Are you sure you want to logout this device? This will also disable the push notification to this device.", | ||||
|   "typingHint": { | ||||
|     "one": "{} is typing...", | ||||
|     "other": "{} are typing..." | ||||
|   }, | ||||
|   "authDeviceEditLabel": "Edit Label", | ||||
|   "authDeviceLabelTitle": "Edit Device Label", | ||||
|   "authDeviceLabelHint": "Enter a name for this device", | ||||
| @@ -439,6 +479,21 @@ | ||||
|   "contactMethodSetPrimary": "Set as Primary", | ||||
|   "contactMethodSetPrimaryHint": "Set this contact method as your primary contact method for account recovery and notifications", | ||||
|   "contactMethodDeleteHint": "Are you sure to delete this contact method? This action cannot be undone.", | ||||
|   "chatNotifyLevel": "Notify Level", | ||||
|   "chatNotifyLevelDescription": "Decide how many notifications you will receive.", | ||||
|   "chatNotifyLevelAll": "All", | ||||
|   "chatNotifyLevelMention": "Mentions", | ||||
|   "chatNotifyLevelNone": "None", | ||||
|   "chatNotifyLevelUpdated": "The notify level has been updated to {}.", | ||||
|   "chatBreak": "Take a Break", | ||||
|   "chatBreakDescription": "Set a time, before that time, your notification level will be metions only, to take a break of the current topic they're talking about.", | ||||
|   "chatBreakClear": "Clear the break time", | ||||
|   "chatBreakHour": "{} break", | ||||
|   "chatBreakDay": "{} day break", | ||||
|   "chatBreakSet": "Break set for {}", | ||||
|   "chatBreakCleared": "Chat break has been cleared.", | ||||
|   "chatBreakCustom": "Custom duration", | ||||
|   "chatBreakEnterMinutes": "Enter minutes", | ||||
|   "firstName": "First Name", | ||||
|   "middleName": "Middle Name", | ||||
|   "lastName": "Last Name", | ||||
| @@ -520,17 +575,29 @@ | ||||
|   "quickActions": "Quick Actions", | ||||
|   "post": "Post", | ||||
|   "copy": "Copy", | ||||
|   "sendToChat": "Send to Chat", | ||||
|   "failedToShareToPost": "Failed to share to post: {}", | ||||
|   "shareToChatComingSoon": "Share to chat functionality coming soon", | ||||
|   "failedToShareToChat": "Failed to share to chat: {}", | ||||
|   "shareToSpecificChatComingSoon": "Share to {} coming soon", | ||||
|   "directChat": "Direct Chat", | ||||
|   "systemShareComingSoon": "System share functionality coming soon", | ||||
|   "failedToShareToSystem": "Failed to share to system: {}", | ||||
|   "failedToCopy": "Failed to copy: {}", | ||||
|   "noChatRoomsAvailable": "No chat rooms available", | ||||
|   "failedToLoadChats": "Failed to load chats", | ||||
|   "contentToShare": "Content to share:", | ||||
|   "unknownChat": "Unknown Chat", | ||||
|   "addAdditionalMessage": "Add additional message...", | ||||
|   "uploadingFiles": "Uploading files...", | ||||
|   "sharedSuccessfully": "Shared successfully!", | ||||
|   "shareSuccess": "Shared successfully!", | ||||
|   "shareToSpecificChatSuccess": "Shared to {} successfully!", | ||||
|   "wouldYouLikeToGoToChat": "Would you like to go to the chat?", | ||||
|   "no": "No", | ||||
|   "yes": "Yes", | ||||
|   "navigateToChat": "Navigate to Chat", | ||||
|   "wouldYouLikeToNavigateToChat": "Would you like to navigate to the chat?", | ||||
|   "abuseReport": "Report", | ||||
|   "abuseReportTitle": "Report Content", | ||||
|   "abuseReportDescription": "Help us keep the community safe by reporting inappropriate content or behavior.", | ||||
| @@ -564,5 +631,24 @@ | ||||
|   "realmJoinSuccess": "Successfully joined the realm.", | ||||
|   "discoverRealms": "Discover Realms", | ||||
|   "discoverPublishers": "Discover Publishers", | ||||
|   "search": "Search" | ||||
|   "search": "Search", | ||||
|   "publisherMembers": "Collaborators", | ||||
|   "developerHub": "Developer Hub", | ||||
|   "developerHubUnselectedHint": "Select a developer to see stats or enroll a new one.", | ||||
|   "enrollDeveloper": "Enroll as a Developer", | ||||
|   "enrollDeveloperHint": "Enroll one of your publishers to become a developer.", | ||||
|   "noPublishersToEnroll": "You don't have any publishers that can be enrolled as a developer.", | ||||
|   "totalCustomApps": "Total Custom Apps", | ||||
|   "customApps": "Custom Apps", | ||||
|   "noCustomApps": "No custom apps yet.", | ||||
|   "createCustomApp": "Create Custom App", | ||||
|   "editCustomApp": "Edit Custom App", | ||||
|   "publicRealm": "Public Realm", | ||||
|   "publicRealmDescription": "Anyone can preview the content of this realm.", | ||||
|   "communityRealm": "Community Realm", | ||||
|   "communityRealmDescription": "Anyone can join this realm and participate in discussions. And will show in the discover page & feed.", | ||||
|   "publicChat": "Public Chat", | ||||
|   "publicChatDescription": "Anyone can preview the content of this chat. Including unjoined bots.", | ||||
|   "communityChat": "Community Chat", | ||||
|   "communityChatDescription": "Anyone can join this chat and participate in discussions." | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import 'package:firebase_core/firebase_core.dart'; | ||||
| import 'package:firebase_messaging/firebase_messaging.dart'; | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:image_picker_android/image_picker_android.dart'; | ||||
| @@ -158,6 +159,28 @@ class IslandApp extends HookConsumerWidget { | ||||
|     } | ||||
|  | ||||
|     useEffect(() { | ||||
|       const channel = MethodChannel('dev.solsynth.solian/notifications'); | ||||
|  | ||||
|       Future<void> handleInitialLink() async { | ||||
|         final String? link = await channel.invokeMethod('initialLink'); | ||||
|         if (link != null) { | ||||
|           final router = ref.read(routerProvider); | ||||
|           router.go(link); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       if (!kIsWeb && Platform.isAndroid) { | ||||
|         handleInitialLink(); | ||||
|       } | ||||
|  | ||||
|       channel.setMethodCallHandler((call) async { | ||||
|         if (call.method == 'newLink') { | ||||
|           final String link = call.arguments; | ||||
|           final router = ref.read(routerProvider); | ||||
|           router.go(link); | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|       // When the app is opened from a terminated state. | ||||
|       FirebaseMessaging.instance.getInitialMessage().then((message) { | ||||
|         if (message != null) { | ||||
|   | ||||
							
								
								
									
										71
									
								
								lib/models/custom_app.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								lib/models/custom_app.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
| import 'package:island/models/file.dart'; | ||||
| import 'package:island/models/user.dart'; | ||||
|  | ||||
| part 'custom_app.freezed.dart'; | ||||
| part 'custom_app.g.dart'; | ||||
|  | ||||
| @freezed | ||||
| sealed class CustomApp with _$CustomApp { | ||||
|   const factory CustomApp({ | ||||
|     @Default('') String id, | ||||
|     @Default('') String slug, | ||||
|     @Default('') String name, | ||||
|     String? description, | ||||
|     @Default(0) int status, | ||||
|     SnCloudFile? picture, | ||||
|     SnCloudFile? background, | ||||
|     SnVerificationMark? verification, | ||||
|     CustomAppOauthConfig? oauthConfig, | ||||
|     CustomAppLinks? links, | ||||
|     @Default([]) List<CustomAppSecret> secrets, | ||||
|     @Default('') String publisherId, | ||||
|   }) = _CustomApp; | ||||
|  | ||||
|   factory CustomApp.fromJson(Map<String, dynamic> json) => | ||||
|       _$CustomAppFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| sealed class CustomAppLinks with _$CustomAppLinks { | ||||
|   const factory CustomAppLinks({ | ||||
|     String? homePage, | ||||
|     String? privacyPolicy, | ||||
|     String? termsOfService, | ||||
|   }) = _CustomAppLinks; | ||||
|  | ||||
|   factory CustomAppLinks.fromJson(Map<String, dynamic> json) => | ||||
|       _$CustomAppLinksFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| sealed class CustomAppOauthConfig with _$CustomAppOauthConfig { | ||||
|   const factory CustomAppOauthConfig({ | ||||
|     String? clientUri, | ||||
|     @Default([]) List<String> redirectUris, | ||||
|     List<String>? postLogoutRedirectUris, | ||||
|     @Default(['openid', 'profile', 'email']) List<String> allowedScopes, | ||||
|     @Default(['authorization_code', 'refresh_token']) | ||||
|     List<String> allowedGrantTypes, | ||||
|     @Default(true) bool requirePkce, | ||||
|     @Default(false) bool allowOfflineAccess, | ||||
|   }) = _CustomAppOauthConfig; | ||||
|  | ||||
|   factory CustomAppOauthConfig.fromJson(Map<String, dynamic> json) => | ||||
|       _$CustomAppOauthConfigFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| sealed class CustomAppSecret with _$CustomAppSecret { | ||||
|   const factory CustomAppSecret({ | ||||
|     @Default('') String id, | ||||
|     @Default('') String secret, | ||||
|     String? description, | ||||
|     DateTime? expiredAt, | ||||
|     @Default(false) bool isOidc, | ||||
|     @Default('') String appId, | ||||
|   }) = _CustomAppSecret; | ||||
|  | ||||
|   factory CustomAppSecret.fromJson(Map<String, dynamic> json) => | ||||
|       _$CustomAppSecretFromJson(json); | ||||
| } | ||||
							
								
								
									
										771
									
								
								lib/models/custom_app.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										771
									
								
								lib/models/custom_app.freezed.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,771 @@ | ||||
| // dart format width=80 | ||||
| // coverage:ignore-file | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark | ||||
|  | ||||
| part of 'custom_app.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // FreezedGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| // dart format off | ||||
| T _$identity<T>(T value) => value; | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$CustomApp { | ||||
|  | ||||
|  String get id; String get slug; String get name; String? get description; int get status; SnCloudFile? get picture; SnCloudFile? get background; SnVerificationMark? get verification; CustomAppOauthConfig? get oauthConfig; CustomAppLinks? get links; List<CustomAppSecret> get secrets; String get publisherId; | ||||
| /// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppCopyWith<CustomApp> get copyWith => _$CustomAppCopyWithImpl<CustomApp>(this as CustomApp, _$identity); | ||||
|  | ||||
|   /// Serializes this CustomApp to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is CustomApp&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.status, status) || other.status == status)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.oauthConfig, oauthConfig) || other.oauthConfig == oauthConfig)&&(identical(other.links, links) || other.links == links)&&const DeepCollectionEquality().equals(other.secrets, secrets)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,slug,name,description,status,picture,background,verification,oauthConfig,links,const DeepCollectionEquality().hash(secrets),publisherId); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomApp(id: $id, slug: $slug, name: $name, description: $description, status: $status, picture: $picture, background: $background, verification: $verification, oauthConfig: $oauthConfig, links: $links, secrets: $secrets, publisherId: $publisherId)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $CustomAppCopyWith<$Res>  { | ||||
|   factory $CustomAppCopyWith(CustomApp value, $Res Function(CustomApp) _then) = _$CustomAppCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String id, String slug, String name, String? description, int status, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, CustomAppOauthConfig? oauthConfig, CustomAppLinks? links, List<CustomAppSecret> secrets, String publisherId | ||||
| }); | ||||
|  | ||||
|  | ||||
| $SnCloudFileCopyWith<$Res>? get picture;$SnCloudFileCopyWith<$Res>? get background;$SnVerificationMarkCopyWith<$Res>? get verification;$CustomAppOauthConfigCopyWith<$Res>? get oauthConfig;$CustomAppLinksCopyWith<$Res>? get links; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$CustomAppCopyWithImpl<$Res> | ||||
|     implements $CustomAppCopyWith<$Res> { | ||||
|   _$CustomAppCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final CustomApp _self; | ||||
|   final $Res Function(CustomApp) _then; | ||||
|  | ||||
| /// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = null,Object? description = freezed,Object? status = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? oauthConfig = freezed,Object? links = freezed,Object? secrets = null,Object? publisherId = null,}) { | ||||
|   return _then(_self.copyWith( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||
| as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||
| as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable | ||||
| as String?,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable | ||||
| as int,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable | ||||
| as SnVerificationMark?,oauthConfig: freezed == oauthConfig ? _self.oauthConfig : oauthConfig // ignore: cast_nullable_to_non_nullable | ||||
| as CustomAppOauthConfig?,links: freezed == links ? _self.links : links // ignore: cast_nullable_to_non_nullable | ||||
| as CustomAppLinks?,secrets: null == secrets ? _self.secrets : secrets // ignore: cast_nullable_to_non_nullable | ||||
| as List<CustomAppSecret>,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable | ||||
| as String, | ||||
|   )); | ||||
| } | ||||
| /// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get picture { | ||||
|     if (_self.picture == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.picture!, (value) { | ||||
|     return _then(_self.copyWith(picture: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get background { | ||||
|     if (_self.background == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.background!, (value) { | ||||
|     return _then(_self.copyWith(background: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnVerificationMarkCopyWith<$Res>? get verification { | ||||
|     if (_self.verification == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) { | ||||
|     return _then(_self.copyWith(verification: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppOauthConfigCopyWith<$Res>? get oauthConfig { | ||||
|     if (_self.oauthConfig == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $CustomAppOauthConfigCopyWith<$Res>(_self.oauthConfig!, (value) { | ||||
|     return _then(_self.copyWith(oauthConfig: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppLinksCopyWith<$Res>? get links { | ||||
|     if (_self.links == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $CustomAppLinksCopyWith<$Res>(_self.links!, (value) { | ||||
|     return _then(_self.copyWith(links: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _CustomApp implements CustomApp { | ||||
|   const _CustomApp({this.id = '', this.slug = '', this.name = '', this.description, this.status = 0, this.picture, this.background, this.verification, this.oauthConfig, this.links, final  List<CustomAppSecret> secrets = const [], this.publisherId = ''}): _secrets = secrets; | ||||
|   factory _CustomApp.fromJson(Map<String, dynamic> json) => _$CustomAppFromJson(json); | ||||
|  | ||||
| @override@JsonKey() final  String id; | ||||
| @override@JsonKey() final  String slug; | ||||
| @override@JsonKey() final  String name; | ||||
| @override final  String? description; | ||||
| @override@JsonKey() final  int status; | ||||
| @override final  SnCloudFile? picture; | ||||
| @override final  SnCloudFile? background; | ||||
| @override final  SnVerificationMark? verification; | ||||
| @override final  CustomAppOauthConfig? oauthConfig; | ||||
| @override final  CustomAppLinks? links; | ||||
|  final  List<CustomAppSecret> _secrets; | ||||
| @override@JsonKey() List<CustomAppSecret> get secrets { | ||||
|   if (_secrets is EqualUnmodifiableListView) return _secrets; | ||||
|   // ignore: implicit_dynamic_type | ||||
|   return EqualUnmodifiableListView(_secrets); | ||||
| } | ||||
|  | ||||
| @override@JsonKey() final  String publisherId; | ||||
|  | ||||
| /// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$CustomAppCopyWith<_CustomApp> get copyWith => __$CustomAppCopyWithImpl<_CustomApp>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$CustomAppToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _CustomApp&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.status, status) || other.status == status)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.oauthConfig, oauthConfig) || other.oauthConfig == oauthConfig)&&(identical(other.links, links) || other.links == links)&&const DeepCollectionEquality().equals(other._secrets, _secrets)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,slug,name,description,status,picture,background,verification,oauthConfig,links,const DeepCollectionEquality().hash(_secrets),publisherId); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomApp(id: $id, slug: $slug, name: $name, description: $description, status: $status, picture: $picture, background: $background, verification: $verification, oauthConfig: $oauthConfig, links: $links, secrets: $secrets, publisherId: $publisherId)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$CustomAppCopyWith<$Res> implements $CustomAppCopyWith<$Res> { | ||||
|   factory _$CustomAppCopyWith(_CustomApp value, $Res Function(_CustomApp) _then) = __$CustomAppCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String id, String slug, String name, String? description, int status, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, CustomAppOauthConfig? oauthConfig, CustomAppLinks? links, List<CustomAppSecret> secrets, String publisherId | ||||
| }); | ||||
|  | ||||
|  | ||||
| @override $SnCloudFileCopyWith<$Res>? get picture;@override $SnCloudFileCopyWith<$Res>? get background;@override $SnVerificationMarkCopyWith<$Res>? get verification;@override $CustomAppOauthConfigCopyWith<$Res>? get oauthConfig;@override $CustomAppLinksCopyWith<$Res>? get links; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$CustomAppCopyWithImpl<$Res> | ||||
|     implements _$CustomAppCopyWith<$Res> { | ||||
|   __$CustomAppCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _CustomApp _self; | ||||
|   final $Res Function(_CustomApp) _then; | ||||
|  | ||||
| /// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = null,Object? description = freezed,Object? status = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? oauthConfig = freezed,Object? links = freezed,Object? secrets = null,Object? publisherId = null,}) { | ||||
|   return _then(_CustomApp( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||
| as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||
| as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable | ||||
| as String?,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable | ||||
| as int,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable | ||||
| as SnVerificationMark?,oauthConfig: freezed == oauthConfig ? _self.oauthConfig : oauthConfig // ignore: cast_nullable_to_non_nullable | ||||
| as CustomAppOauthConfig?,links: freezed == links ? _self.links : links // ignore: cast_nullable_to_non_nullable | ||||
| as CustomAppLinks?,secrets: null == secrets ? _self._secrets : secrets // ignore: cast_nullable_to_non_nullable | ||||
| as List<CustomAppSecret>,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable | ||||
| as String, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| /// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get picture { | ||||
|     if (_self.picture == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.picture!, (value) { | ||||
|     return _then(_self.copyWith(picture: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get background { | ||||
|     if (_self.background == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.background!, (value) { | ||||
|     return _then(_self.copyWith(background: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnVerificationMarkCopyWith<$Res>? get verification { | ||||
|     if (_self.verification == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) { | ||||
|     return _then(_self.copyWith(verification: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppOauthConfigCopyWith<$Res>? get oauthConfig { | ||||
|     if (_self.oauthConfig == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $CustomAppOauthConfigCopyWith<$Res>(_self.oauthConfig!, (value) { | ||||
|     return _then(_self.copyWith(oauthConfig: value)); | ||||
|   }); | ||||
| }/// Create a copy of CustomApp | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppLinksCopyWith<$Res>? get links { | ||||
|     if (_self.links == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $CustomAppLinksCopyWith<$Res>(_self.links!, (value) { | ||||
|     return _then(_self.copyWith(links: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$CustomAppLinks { | ||||
|  | ||||
|  String? get homePage; String? get privacyPolicy; String? get termsOfService; | ||||
| /// Create a copy of CustomAppLinks | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppLinksCopyWith<CustomAppLinks> get copyWith => _$CustomAppLinksCopyWithImpl<CustomAppLinks>(this as CustomAppLinks, _$identity); | ||||
|  | ||||
|   /// Serializes this CustomAppLinks to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is CustomAppLinks&&(identical(other.homePage, homePage) || other.homePage == homePage)&&(identical(other.privacyPolicy, privacyPolicy) || other.privacyPolicy == privacyPolicy)&&(identical(other.termsOfService, termsOfService) || other.termsOfService == termsOfService)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,homePage,privacyPolicy,termsOfService); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomAppLinks(homePage: $homePage, privacyPolicy: $privacyPolicy, termsOfService: $termsOfService)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $CustomAppLinksCopyWith<$Res>  { | ||||
|   factory $CustomAppLinksCopyWith(CustomAppLinks value, $Res Function(CustomAppLinks) _then) = _$CustomAppLinksCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String? homePage, String? privacyPolicy, String? termsOfService | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$CustomAppLinksCopyWithImpl<$Res> | ||||
|     implements $CustomAppLinksCopyWith<$Res> { | ||||
|   _$CustomAppLinksCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final CustomAppLinks _self; | ||||
|   final $Res Function(CustomAppLinks) _then; | ||||
|  | ||||
| /// Create a copy of CustomAppLinks | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? homePage = freezed,Object? privacyPolicy = freezed,Object? termsOfService = freezed,}) { | ||||
|   return _then(_self.copyWith( | ||||
| homePage: freezed == homePage ? _self.homePage : homePage // ignore: cast_nullable_to_non_nullable | ||||
| as String?,privacyPolicy: freezed == privacyPolicy ? _self.privacyPolicy : privacyPolicy // ignore: cast_nullable_to_non_nullable | ||||
| as String?,termsOfService: freezed == termsOfService ? _self.termsOfService : termsOfService // ignore: cast_nullable_to_non_nullable | ||||
| as String?, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _CustomAppLinks implements CustomAppLinks { | ||||
|   const _CustomAppLinks({this.homePage, this.privacyPolicy, this.termsOfService}); | ||||
|   factory _CustomAppLinks.fromJson(Map<String, dynamic> json) => _$CustomAppLinksFromJson(json); | ||||
|  | ||||
| @override final  String? homePage; | ||||
| @override final  String? privacyPolicy; | ||||
| @override final  String? termsOfService; | ||||
|  | ||||
| /// Create a copy of CustomAppLinks | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$CustomAppLinksCopyWith<_CustomAppLinks> get copyWith => __$CustomAppLinksCopyWithImpl<_CustomAppLinks>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$CustomAppLinksToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _CustomAppLinks&&(identical(other.homePage, homePage) || other.homePage == homePage)&&(identical(other.privacyPolicy, privacyPolicy) || other.privacyPolicy == privacyPolicy)&&(identical(other.termsOfService, termsOfService) || other.termsOfService == termsOfService)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,homePage,privacyPolicy,termsOfService); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomAppLinks(homePage: $homePage, privacyPolicy: $privacyPolicy, termsOfService: $termsOfService)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$CustomAppLinksCopyWith<$Res> implements $CustomAppLinksCopyWith<$Res> { | ||||
|   factory _$CustomAppLinksCopyWith(_CustomAppLinks value, $Res Function(_CustomAppLinks) _then) = __$CustomAppLinksCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String? homePage, String? privacyPolicy, String? termsOfService | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$CustomAppLinksCopyWithImpl<$Res> | ||||
|     implements _$CustomAppLinksCopyWith<$Res> { | ||||
|   __$CustomAppLinksCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _CustomAppLinks _self; | ||||
|   final $Res Function(_CustomAppLinks) _then; | ||||
|  | ||||
| /// Create a copy of CustomAppLinks | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? homePage = freezed,Object? privacyPolicy = freezed,Object? termsOfService = freezed,}) { | ||||
|   return _then(_CustomAppLinks( | ||||
| homePage: freezed == homePage ? _self.homePage : homePage // ignore: cast_nullable_to_non_nullable | ||||
| as String?,privacyPolicy: freezed == privacyPolicy ? _self.privacyPolicy : privacyPolicy // ignore: cast_nullable_to_non_nullable | ||||
| as String?,termsOfService: freezed == termsOfService ? _self.termsOfService : termsOfService // ignore: cast_nullable_to_non_nullable | ||||
| as String?, | ||||
|   )); | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$CustomAppOauthConfig { | ||||
|  | ||||
|  String? get clientUri; List<String> get redirectUris; List<String>? get postLogoutRedirectUris; List<String> get allowedScopes; List<String> get allowedGrantTypes; bool get requirePkce; bool get allowOfflineAccess; | ||||
| /// Create a copy of CustomAppOauthConfig | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppOauthConfigCopyWith<CustomAppOauthConfig> get copyWith => _$CustomAppOauthConfigCopyWithImpl<CustomAppOauthConfig>(this as CustomAppOauthConfig, _$identity); | ||||
|  | ||||
|   /// Serializes this CustomAppOauthConfig to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is CustomAppOauthConfig&&(identical(other.clientUri, clientUri) || other.clientUri == clientUri)&&const DeepCollectionEquality().equals(other.redirectUris, redirectUris)&&const DeepCollectionEquality().equals(other.postLogoutRedirectUris, postLogoutRedirectUris)&&const DeepCollectionEquality().equals(other.allowedScopes, allowedScopes)&&const DeepCollectionEquality().equals(other.allowedGrantTypes, allowedGrantTypes)&&(identical(other.requirePkce, requirePkce) || other.requirePkce == requirePkce)&&(identical(other.allowOfflineAccess, allowOfflineAccess) || other.allowOfflineAccess == allowOfflineAccess)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,clientUri,const DeepCollectionEquality().hash(redirectUris),const DeepCollectionEquality().hash(postLogoutRedirectUris),const DeepCollectionEquality().hash(allowedScopes),const DeepCollectionEquality().hash(allowedGrantTypes),requirePkce,allowOfflineAccess); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomAppOauthConfig(clientUri: $clientUri, redirectUris: $redirectUris, postLogoutRedirectUris: $postLogoutRedirectUris, allowedScopes: $allowedScopes, allowedGrantTypes: $allowedGrantTypes, requirePkce: $requirePkce, allowOfflineAccess: $allowOfflineAccess)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $CustomAppOauthConfigCopyWith<$Res>  { | ||||
|   factory $CustomAppOauthConfigCopyWith(CustomAppOauthConfig value, $Res Function(CustomAppOauthConfig) _then) = _$CustomAppOauthConfigCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String? clientUri, List<String> redirectUris, List<String>? postLogoutRedirectUris, List<String> allowedScopes, List<String> allowedGrantTypes, bool requirePkce, bool allowOfflineAccess | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$CustomAppOauthConfigCopyWithImpl<$Res> | ||||
|     implements $CustomAppOauthConfigCopyWith<$Res> { | ||||
|   _$CustomAppOauthConfigCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final CustomAppOauthConfig _self; | ||||
|   final $Res Function(CustomAppOauthConfig) _then; | ||||
|  | ||||
| /// Create a copy of CustomAppOauthConfig | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? clientUri = freezed,Object? redirectUris = null,Object? postLogoutRedirectUris = freezed,Object? allowedScopes = null,Object? allowedGrantTypes = null,Object? requirePkce = null,Object? allowOfflineAccess = null,}) { | ||||
|   return _then(_self.copyWith( | ||||
| clientUri: freezed == clientUri ? _self.clientUri : clientUri // ignore: cast_nullable_to_non_nullable | ||||
| as String?,redirectUris: null == redirectUris ? _self.redirectUris : redirectUris // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>,postLogoutRedirectUris: freezed == postLogoutRedirectUris ? _self.postLogoutRedirectUris : postLogoutRedirectUris // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>?,allowedScopes: null == allowedScopes ? _self.allowedScopes : allowedScopes // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>,allowedGrantTypes: null == allowedGrantTypes ? _self.allowedGrantTypes : allowedGrantTypes // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>,requirePkce: null == requirePkce ? _self.requirePkce : requirePkce // ignore: cast_nullable_to_non_nullable | ||||
| as bool,allowOfflineAccess: null == allowOfflineAccess ? _self.allowOfflineAccess : allowOfflineAccess // ignore: cast_nullable_to_non_nullable | ||||
| as bool, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _CustomAppOauthConfig implements CustomAppOauthConfig { | ||||
|   const _CustomAppOauthConfig({this.clientUri, final  List<String> redirectUris = const [], final  List<String>? postLogoutRedirectUris, final  List<String> allowedScopes = const ['openid', 'profile', 'email'], final  List<String> allowedGrantTypes = const ['authorization_code', 'refresh_token'], this.requirePkce = true, this.allowOfflineAccess = false}): _redirectUris = redirectUris,_postLogoutRedirectUris = postLogoutRedirectUris,_allowedScopes = allowedScopes,_allowedGrantTypes = allowedGrantTypes; | ||||
|   factory _CustomAppOauthConfig.fromJson(Map<String, dynamic> json) => _$CustomAppOauthConfigFromJson(json); | ||||
|  | ||||
| @override final  String? clientUri; | ||||
|  final  List<String> _redirectUris; | ||||
| @override@JsonKey() List<String> get redirectUris { | ||||
|   if (_redirectUris is EqualUnmodifiableListView) return _redirectUris; | ||||
|   // ignore: implicit_dynamic_type | ||||
|   return EqualUnmodifiableListView(_redirectUris); | ||||
| } | ||||
|  | ||||
|  final  List<String>? _postLogoutRedirectUris; | ||||
| @override List<String>? get postLogoutRedirectUris { | ||||
|   final value = _postLogoutRedirectUris; | ||||
|   if (value == null) return null; | ||||
|   if (_postLogoutRedirectUris is EqualUnmodifiableListView) return _postLogoutRedirectUris; | ||||
|   // ignore: implicit_dynamic_type | ||||
|   return EqualUnmodifiableListView(value); | ||||
| } | ||||
|  | ||||
|  final  List<String> _allowedScopes; | ||||
| @override@JsonKey() List<String> get allowedScopes { | ||||
|   if (_allowedScopes is EqualUnmodifiableListView) return _allowedScopes; | ||||
|   // ignore: implicit_dynamic_type | ||||
|   return EqualUnmodifiableListView(_allowedScopes); | ||||
| } | ||||
|  | ||||
|  final  List<String> _allowedGrantTypes; | ||||
| @override@JsonKey() List<String> get allowedGrantTypes { | ||||
|   if (_allowedGrantTypes is EqualUnmodifiableListView) return _allowedGrantTypes; | ||||
|   // ignore: implicit_dynamic_type | ||||
|   return EqualUnmodifiableListView(_allowedGrantTypes); | ||||
| } | ||||
|  | ||||
| @override@JsonKey() final  bool requirePkce; | ||||
| @override@JsonKey() final  bool allowOfflineAccess; | ||||
|  | ||||
| /// Create a copy of CustomAppOauthConfig | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$CustomAppOauthConfigCopyWith<_CustomAppOauthConfig> get copyWith => __$CustomAppOauthConfigCopyWithImpl<_CustomAppOauthConfig>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$CustomAppOauthConfigToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _CustomAppOauthConfig&&(identical(other.clientUri, clientUri) || other.clientUri == clientUri)&&const DeepCollectionEquality().equals(other._redirectUris, _redirectUris)&&const DeepCollectionEquality().equals(other._postLogoutRedirectUris, _postLogoutRedirectUris)&&const DeepCollectionEquality().equals(other._allowedScopes, _allowedScopes)&&const DeepCollectionEquality().equals(other._allowedGrantTypes, _allowedGrantTypes)&&(identical(other.requirePkce, requirePkce) || other.requirePkce == requirePkce)&&(identical(other.allowOfflineAccess, allowOfflineAccess) || other.allowOfflineAccess == allowOfflineAccess)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,clientUri,const DeepCollectionEquality().hash(_redirectUris),const DeepCollectionEquality().hash(_postLogoutRedirectUris),const DeepCollectionEquality().hash(_allowedScopes),const DeepCollectionEquality().hash(_allowedGrantTypes),requirePkce,allowOfflineAccess); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomAppOauthConfig(clientUri: $clientUri, redirectUris: $redirectUris, postLogoutRedirectUris: $postLogoutRedirectUris, allowedScopes: $allowedScopes, allowedGrantTypes: $allowedGrantTypes, requirePkce: $requirePkce, allowOfflineAccess: $allowOfflineAccess)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$CustomAppOauthConfigCopyWith<$Res> implements $CustomAppOauthConfigCopyWith<$Res> { | ||||
|   factory _$CustomAppOauthConfigCopyWith(_CustomAppOauthConfig value, $Res Function(_CustomAppOauthConfig) _then) = __$CustomAppOauthConfigCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String? clientUri, List<String> redirectUris, List<String>? postLogoutRedirectUris, List<String> allowedScopes, List<String> allowedGrantTypes, bool requirePkce, bool allowOfflineAccess | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$CustomAppOauthConfigCopyWithImpl<$Res> | ||||
|     implements _$CustomAppOauthConfigCopyWith<$Res> { | ||||
|   __$CustomAppOauthConfigCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _CustomAppOauthConfig _self; | ||||
|   final $Res Function(_CustomAppOauthConfig) _then; | ||||
|  | ||||
| /// Create a copy of CustomAppOauthConfig | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? clientUri = freezed,Object? redirectUris = null,Object? postLogoutRedirectUris = freezed,Object? allowedScopes = null,Object? allowedGrantTypes = null,Object? requirePkce = null,Object? allowOfflineAccess = null,}) { | ||||
|   return _then(_CustomAppOauthConfig( | ||||
| clientUri: freezed == clientUri ? _self.clientUri : clientUri // ignore: cast_nullable_to_non_nullable | ||||
| as String?,redirectUris: null == redirectUris ? _self._redirectUris : redirectUris // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>,postLogoutRedirectUris: freezed == postLogoutRedirectUris ? _self._postLogoutRedirectUris : postLogoutRedirectUris // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>?,allowedScopes: null == allowedScopes ? _self._allowedScopes : allowedScopes // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>,allowedGrantTypes: null == allowedGrantTypes ? _self._allowedGrantTypes : allowedGrantTypes // ignore: cast_nullable_to_non_nullable | ||||
| as List<String>,requirePkce: null == requirePkce ? _self.requirePkce : requirePkce // ignore: cast_nullable_to_non_nullable | ||||
| as bool,allowOfflineAccess: null == allowOfflineAccess ? _self.allowOfflineAccess : allowOfflineAccess // ignore: cast_nullable_to_non_nullable | ||||
| as bool, | ||||
|   )); | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$CustomAppSecret { | ||||
|  | ||||
|  String get id; String get secret; String? get description; DateTime? get expiredAt; bool get isOidc; String get appId; | ||||
| /// Create a copy of CustomAppSecret | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $CustomAppSecretCopyWith<CustomAppSecret> get copyWith => _$CustomAppSecretCopyWithImpl<CustomAppSecret>(this as CustomAppSecret, _$identity); | ||||
|  | ||||
|   /// Serializes this CustomAppSecret to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is CustomAppSecret&&(identical(other.id, id) || other.id == id)&&(identical(other.secret, secret) || other.secret == secret)&&(identical(other.description, description) || other.description == description)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.isOidc, isOidc) || other.isOidc == isOidc)&&(identical(other.appId, appId) || other.appId == appId)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,secret,description,expiredAt,isOidc,appId); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomAppSecret(id: $id, secret: $secret, description: $description, expiredAt: $expiredAt, isOidc: $isOidc, appId: $appId)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $CustomAppSecretCopyWith<$Res>  { | ||||
|   factory $CustomAppSecretCopyWith(CustomAppSecret value, $Res Function(CustomAppSecret) _then) = _$CustomAppSecretCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String id, String secret, String? description, DateTime? expiredAt, bool isOidc, String appId | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$CustomAppSecretCopyWithImpl<$Res> | ||||
|     implements $CustomAppSecretCopyWith<$Res> { | ||||
|   _$CustomAppSecretCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final CustomAppSecret _self; | ||||
|   final $Res Function(CustomAppSecret) _then; | ||||
|  | ||||
| /// Create a copy of CustomAppSecret | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? secret = null,Object? description = freezed,Object? expiredAt = freezed,Object? isOidc = null,Object? appId = null,}) { | ||||
|   return _then(_self.copyWith( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,secret: null == secret ? _self.secret : secret // ignore: cast_nullable_to_non_nullable | ||||
| as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable | ||||
| as String?,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,isOidc: null == isOidc ? _self.isOidc : isOidc // ignore: cast_nullable_to_non_nullable | ||||
| as bool,appId: null == appId ? _self.appId : appId // ignore: cast_nullable_to_non_nullable | ||||
| as String, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _CustomAppSecret implements CustomAppSecret { | ||||
|   const _CustomAppSecret({this.id = '', this.secret = '', this.description, this.expiredAt, this.isOidc = false, this.appId = ''}); | ||||
|   factory _CustomAppSecret.fromJson(Map<String, dynamic> json) => _$CustomAppSecretFromJson(json); | ||||
|  | ||||
| @override@JsonKey() final  String id; | ||||
| @override@JsonKey() final  String secret; | ||||
| @override final  String? description; | ||||
| @override final  DateTime? expiredAt; | ||||
| @override@JsonKey() final  bool isOidc; | ||||
| @override@JsonKey() final  String appId; | ||||
|  | ||||
| /// Create a copy of CustomAppSecret | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$CustomAppSecretCopyWith<_CustomAppSecret> get copyWith => __$CustomAppSecretCopyWithImpl<_CustomAppSecret>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$CustomAppSecretToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _CustomAppSecret&&(identical(other.id, id) || other.id == id)&&(identical(other.secret, secret) || other.secret == secret)&&(identical(other.description, description) || other.description == description)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.isOidc, isOidc) || other.isOidc == isOidc)&&(identical(other.appId, appId) || other.appId == appId)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,secret,description,expiredAt,isOidc,appId); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'CustomAppSecret(id: $id, secret: $secret, description: $description, expiredAt: $expiredAt, isOidc: $isOidc, appId: $appId)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$CustomAppSecretCopyWith<$Res> implements $CustomAppSecretCopyWith<$Res> { | ||||
|   factory _$CustomAppSecretCopyWith(_CustomAppSecret value, $Res Function(_CustomAppSecret) _then) = __$CustomAppSecretCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String id, String secret, String? description, DateTime? expiredAt, bool isOidc, String appId | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$CustomAppSecretCopyWithImpl<$Res> | ||||
|     implements _$CustomAppSecretCopyWith<$Res> { | ||||
|   __$CustomAppSecretCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _CustomAppSecret _self; | ||||
|   final $Res Function(_CustomAppSecret) _then; | ||||
|  | ||||
| /// Create a copy of CustomAppSecret | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? secret = null,Object? description = freezed,Object? expiredAt = freezed,Object? isOidc = null,Object? appId = null,}) { | ||||
|   return _then(_CustomAppSecret( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,secret: null == secret ? _self.secret : secret // ignore: cast_nullable_to_non_nullable | ||||
| as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable | ||||
| as String?,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,isOidc: null == isOidc ? _self.isOidc : isOidc // ignore: cast_nullable_to_non_nullable | ||||
| as bool,appId: null == appId ? _self.appId : appId // ignore: cast_nullable_to_non_nullable | ||||
| as String, | ||||
|   )); | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| // dart format on | ||||
							
								
								
									
										137
									
								
								lib/models/custom_app.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								lib/models/custom_app.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'custom_app.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // JsonSerializableGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| _CustomApp _$CustomAppFromJson(Map<String, dynamic> json) => _CustomApp( | ||||
|   id: json['id'] as String? ?? '', | ||||
|   slug: json['slug'] as String? ?? '', | ||||
|   name: json['name'] as String? ?? '', | ||||
|   description: json['description'] as String?, | ||||
|   status: (json['status'] as num?)?.toInt() ?? 0, | ||||
|   picture: | ||||
|       json['picture'] == null | ||||
|           ? null | ||||
|           : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), | ||||
|   background: | ||||
|       json['background'] == null | ||||
|           ? null | ||||
|           : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>), | ||||
|   verification: | ||||
|       json['verification'] == null | ||||
|           ? null | ||||
|           : SnVerificationMark.fromJson( | ||||
|             json['verification'] as Map<String, dynamic>, | ||||
|           ), | ||||
|   oauthConfig: | ||||
|       json['oauth_config'] == null | ||||
|           ? null | ||||
|           : CustomAppOauthConfig.fromJson( | ||||
|             json['oauth_config'] as Map<String, dynamic>, | ||||
|           ), | ||||
|   links: | ||||
|       json['links'] == null | ||||
|           ? null | ||||
|           : CustomAppLinks.fromJson(json['links'] as Map<String, dynamic>), | ||||
|   secrets: | ||||
|       (json['secrets'] as List<dynamic>?) | ||||
|           ?.map((e) => CustomAppSecret.fromJson(e as Map<String, dynamic>)) | ||||
|           .toList() ?? | ||||
|       const [], | ||||
|   publisherId: json['publisher_id'] as String? ?? '', | ||||
| ); | ||||
|  | ||||
| Map<String, dynamic> _$CustomAppToJson(_CustomApp instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'slug': instance.slug, | ||||
|       'name': instance.name, | ||||
|       'description': instance.description, | ||||
|       'status': instance.status, | ||||
|       'picture': instance.picture?.toJson(), | ||||
|       'background': instance.background?.toJson(), | ||||
|       'verification': instance.verification?.toJson(), | ||||
|       'oauth_config': instance.oauthConfig?.toJson(), | ||||
|       'links': instance.links?.toJson(), | ||||
|       'secrets': instance.secrets.map((e) => e.toJson()).toList(), | ||||
|       'publisher_id': instance.publisherId, | ||||
|     }; | ||||
|  | ||||
| _CustomAppLinks _$CustomAppLinksFromJson(Map<String, dynamic> json) => | ||||
|     _CustomAppLinks( | ||||
|       homePage: json['home_page'] as String?, | ||||
|       privacyPolicy: json['privacy_policy'] as String?, | ||||
|       termsOfService: json['terms_of_service'] as String?, | ||||
|     ); | ||||
|  | ||||
| Map<String, dynamic> _$CustomAppLinksToJson(_CustomAppLinks instance) => | ||||
|     <String, dynamic>{ | ||||
|       'home_page': instance.homePage, | ||||
|       'privacy_policy': instance.privacyPolicy, | ||||
|       'terms_of_service': instance.termsOfService, | ||||
|     }; | ||||
|  | ||||
| _CustomAppOauthConfig _$CustomAppOauthConfigFromJson( | ||||
|   Map<String, dynamic> json, | ||||
| ) => _CustomAppOauthConfig( | ||||
|   clientUri: json['client_uri'] as String?, | ||||
|   redirectUris: | ||||
|       (json['redirect_uris'] as List<dynamic>?) | ||||
|           ?.map((e) => e as String) | ||||
|           .toList() ?? | ||||
|       const [], | ||||
|   postLogoutRedirectUris: | ||||
|       (json['post_logout_redirect_uris'] as List<dynamic>?) | ||||
|           ?.map((e) => e as String) | ||||
|           .toList(), | ||||
|   allowedScopes: | ||||
|       (json['allowed_scopes'] as List<dynamic>?) | ||||
|           ?.map((e) => e as String) | ||||
|           .toList() ?? | ||||
|       const ['openid', 'profile', 'email'], | ||||
|   allowedGrantTypes: | ||||
|       (json['allowed_grant_types'] as List<dynamic>?) | ||||
|           ?.map((e) => e as String) | ||||
|           .toList() ?? | ||||
|       const ['authorization_code', 'refresh_token'], | ||||
|   requirePkce: json['require_pkce'] as bool? ?? true, | ||||
|   allowOfflineAccess: json['allow_offline_access'] as bool? ?? false, | ||||
| ); | ||||
|  | ||||
| Map<String, dynamic> _$CustomAppOauthConfigToJson( | ||||
|   _CustomAppOauthConfig instance, | ||||
| ) => <String, dynamic>{ | ||||
|   'client_uri': instance.clientUri, | ||||
|   'redirect_uris': instance.redirectUris, | ||||
|   'post_logout_redirect_uris': instance.postLogoutRedirectUris, | ||||
|   'allowed_scopes': instance.allowedScopes, | ||||
|   'allowed_grant_types': instance.allowedGrantTypes, | ||||
|   'require_pkce': instance.requirePkce, | ||||
|   'allow_offline_access': instance.allowOfflineAccess, | ||||
| }; | ||||
|  | ||||
| _CustomAppSecret _$CustomAppSecretFromJson(Map<String, dynamic> json) => | ||||
|     _CustomAppSecret( | ||||
|       id: json['id'] as String? ?? '', | ||||
|       secret: json['secret'] as String? ?? '', | ||||
|       description: json['description'] as String?, | ||||
|       expiredAt: | ||||
|           json['expired_at'] == null | ||||
|               ? null | ||||
|               : DateTime.parse(json['expired_at'] as String), | ||||
|       isOidc: json['is_oidc'] as bool? ?? false, | ||||
|       appId: json['app_id'] as String? ?? '', | ||||
|     ); | ||||
|  | ||||
| Map<String, dynamic> _$CustomAppSecretToJson(_CustomAppSecret instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'secret': instance.secret, | ||||
|       'description': instance.description, | ||||
|       'expired_at': instance.expiredAt?.toIso8601String(), | ||||
|       'is_oidc': instance.isOidc, | ||||
|       'app_id': instance.appId, | ||||
|     }; | ||||
							
								
								
									
										14
									
								
								lib/models/developer.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/models/developer.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
|  | ||||
| part 'developer.freezed.dart'; | ||||
| part 'developer.g.dart'; | ||||
|  | ||||
| @freezed | ||||
| sealed class DeveloperStats with _$DeveloperStats { | ||||
|   const factory DeveloperStats({ | ||||
|     @Default(0) int totalCustomApps, | ||||
|   }) = _DeveloperStats; | ||||
|  | ||||
|   factory DeveloperStats.fromJson(Map<String, dynamic> json) => | ||||
|       _$DeveloperStatsFromJson(json); | ||||
| } | ||||
							
								
								
									
										148
									
								
								lib/models/developer.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								lib/models/developer.freezed.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| // dart format width=80 | ||||
| // coverage:ignore-file | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark | ||||
|  | ||||
| part of 'developer.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // FreezedGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| // dart format off | ||||
| T _$identity<T>(T value) => value; | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$DeveloperStats { | ||||
|  | ||||
|  int get totalCustomApps; | ||||
| /// Create a copy of DeveloperStats | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $DeveloperStatsCopyWith<DeveloperStats> get copyWith => _$DeveloperStatsCopyWithImpl<DeveloperStats>(this as DeveloperStats, _$identity); | ||||
|  | ||||
|   /// Serializes this DeveloperStats to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is DeveloperStats&&(identical(other.totalCustomApps, totalCustomApps) || other.totalCustomApps == totalCustomApps)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,totalCustomApps); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'DeveloperStats(totalCustomApps: $totalCustomApps)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $DeveloperStatsCopyWith<$Res>  { | ||||
|   factory $DeveloperStatsCopyWith(DeveloperStats value, $Res Function(DeveloperStats) _then) = _$DeveloperStatsCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  int totalCustomApps | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$DeveloperStatsCopyWithImpl<$Res> | ||||
|     implements $DeveloperStatsCopyWith<$Res> { | ||||
|   _$DeveloperStatsCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final DeveloperStats _self; | ||||
|   final $Res Function(DeveloperStats) _then; | ||||
|  | ||||
| /// Create a copy of DeveloperStats | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? totalCustomApps = null,}) { | ||||
|   return _then(_self.copyWith( | ||||
| totalCustomApps: null == totalCustomApps ? _self.totalCustomApps : totalCustomApps // ignore: cast_nullable_to_non_nullable | ||||
| as int, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _DeveloperStats implements DeveloperStats { | ||||
|   const _DeveloperStats({this.totalCustomApps = 0}); | ||||
|   factory _DeveloperStats.fromJson(Map<String, dynamic> json) => _$DeveloperStatsFromJson(json); | ||||
|  | ||||
| @override@JsonKey() final  int totalCustomApps; | ||||
|  | ||||
| /// Create a copy of DeveloperStats | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$DeveloperStatsCopyWith<_DeveloperStats> get copyWith => __$DeveloperStatsCopyWithImpl<_DeveloperStats>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$DeveloperStatsToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _DeveloperStats&&(identical(other.totalCustomApps, totalCustomApps) || other.totalCustomApps == totalCustomApps)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,totalCustomApps); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'DeveloperStats(totalCustomApps: $totalCustomApps)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$DeveloperStatsCopyWith<$Res> implements $DeveloperStatsCopyWith<$Res> { | ||||
|   factory _$DeveloperStatsCopyWith(_DeveloperStats value, $Res Function(_DeveloperStats) _then) = __$DeveloperStatsCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  int totalCustomApps | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$DeveloperStatsCopyWithImpl<$Res> | ||||
|     implements _$DeveloperStatsCopyWith<$Res> { | ||||
|   __$DeveloperStatsCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _DeveloperStats _self; | ||||
|   final $Res Function(_DeveloperStats) _then; | ||||
|  | ||||
| /// Create a copy of DeveloperStats | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? totalCustomApps = null,}) { | ||||
|   return _then(_DeveloperStats( | ||||
| totalCustomApps: null == totalCustomApps ? _self.totalCustomApps : totalCustomApps // ignore: cast_nullable_to_non_nullable | ||||
| as int, | ||||
|   )); | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| // dart format on | ||||
							
								
								
									
										15
									
								
								lib/models/developer.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								lib/models/developer.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'developer.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // JsonSerializableGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| _DeveloperStats _$DeveloperStatsFromJson(Map<String, dynamic> json) => | ||||
|     _DeveloperStats( | ||||
|       totalCustomApps: (json['total_custom_apps'] as num?)?.toInt() ?? 0, | ||||
|     ); | ||||
|  | ||||
| Map<String, dynamic> _$DeveloperStatsToJson(_DeveloperStats instance) => | ||||
|     <String, dynamic>{'total_custom_apps': instance.totalCustomApps}; | ||||
| @@ -2,7 +2,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
| import 'package:island/models/file.dart'; | ||||
| import 'package:island/models/post_category.dart'; | ||||
| import 'package:island/models/post_tag.dart'; | ||||
| import 'package:island/models/user.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
|  | ||||
| part 'post.freezed.dart'; | ||||
| part 'post.g.dart'; | ||||
| @@ -32,7 +32,7 @@ sealed class SnPost with _$SnPost { | ||||
|     String? forwardedPostId, | ||||
|     SnPost? forwardedPost, | ||||
|     @Default([]) List<SnCloudFile> attachments, | ||||
|     @Default(SnPublisher()) SnPublisher publisher, | ||||
|     required SnPublisher publisher, | ||||
|     @Default({}) Map<String, int> reactionsCount, | ||||
|     @Default([]) List<dynamic> reactions, | ||||
|     @Default([]) List<PostTag> tags, | ||||
| @@ -47,29 +47,6 @@ sealed class SnPost with _$SnPost { | ||||
|   factory SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| sealed class SnPublisher with _$SnPublisher { | ||||
|   const factory SnPublisher({ | ||||
|     @Default('') String id, | ||||
|     @Default(0) int type, | ||||
|     @Default('') String name, | ||||
|     @Default('') String nick, | ||||
|     @Default('') String bio, | ||||
|     SnCloudFile? picture, | ||||
|     SnCloudFile? background, | ||||
|     SnAccount? account, | ||||
|     String? accountId, | ||||
|     @Default(null) DateTime? createdAt, | ||||
|     @Default(null) DateTime? updatedAt, | ||||
|     DateTime? deletedAt, | ||||
|     String? realmId, | ||||
|     SnVerificationMark? verification, | ||||
|   }) = _SnPublisher; | ||||
|  | ||||
|   factory SnPublisher.fromJson(Map<String, dynamic> json) => | ||||
|       _$SnPublisherFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| sealed class SnPublisherStats with _$SnPublisherStats { | ||||
|   const factory SnPublisherStats({ | ||||
|   | ||||
| @@ -156,7 +156,7 @@ $SnPublisherCopyWith<$Res> get publisher { | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _SnPost implements SnPost { | ||||
|   const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.type = 0, final  Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, final  List<SnCloudFile> attachments = const [], this.publisher = const SnPublisher(), final  Map<String, int> reactionsCount = const {}, final  List<dynamic> reactions = const [], final  List<PostTag> tags = const [], final  List<PostCategory> categories = const [], final  List<dynamic> collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; | ||||
|   const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.type = 0, final  Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, final  List<SnCloudFile> attachments = const [], required this.publisher, final  Map<String, int> reactionsCount = const {}, final  List<dynamic> reactions = const [], final  List<PostTag> tags = const [], final  List<PostCategory> categories = const [], final  List<dynamic> collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; | ||||
|   factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json); | ||||
|  | ||||
| @override final  String id; | ||||
| @@ -195,7 +195,7 @@ class _SnPost implements SnPost { | ||||
|   return EqualUnmodifiableListView(_attachments); | ||||
| } | ||||
|  | ||||
| @override@JsonKey() final  SnPublisher publisher; | ||||
| @override final  SnPublisher publisher; | ||||
|  final  Map<String, int> _reactionsCount; | ||||
| @override@JsonKey() Map<String, int> get reactionsCount { | ||||
|   if (_reactionsCount is EqualUnmodifiableMapView) return _reactionsCount; | ||||
| @@ -373,274 +373,6 @@ $SnPublisherCopyWith<$Res> get publisher { | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$SnPublisher { | ||||
|  | ||||
|  String get id; int get type; String get name; String get nick; String get bio; SnCloudFile? get picture; SnCloudFile? get background; SnAccount? get account; String? get accountId; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; String? get realmId; SnVerificationMark? get verification; | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnPublisherCopyWith<SnPublisher> get copyWith => _$SnPublisherCopyWithImpl<SnPublisher>(this as SnPublisher, _$identity); | ||||
|  | ||||
|   /// Serializes this SnPublisher to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.verification, verification) || other.verification == verification)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId,verification); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId, verification: $verification)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $SnPublisherCopyWith<$Res>  { | ||||
|   factory $SnPublisherCopyWith(SnPublisher value, $Res Function(SnPublisher) _then) = _$SnPublisherCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification | ||||
| }); | ||||
|  | ||||
|  | ||||
| $SnCloudFileCopyWith<$Res>? get picture;$SnCloudFileCopyWith<$Res>? get background;$SnAccountCopyWith<$Res>? get account;$SnVerificationMarkCopyWith<$Res>? get verification; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$SnPublisherCopyWithImpl<$Res> | ||||
|     implements $SnPublisherCopyWith<$Res> { | ||||
|   _$SnPublisherCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final SnPublisher _self; | ||||
|   final $Res Function(SnPublisher) _then; | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { | ||||
|   return _then(_self.copyWith( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||
| as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||
| as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | ||||
| as String,bio: null == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable | ||||
| as String,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable | ||||
| as SnAccount?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable | ||||
| as SnVerificationMark?, | ||||
|   )); | ||||
| } | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get picture { | ||||
|     if (_self.picture == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.picture!, (value) { | ||||
|     return _then(_self.copyWith(picture: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get background { | ||||
|     if (_self.background == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.background!, (value) { | ||||
|     return _then(_self.copyWith(background: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnAccountCopyWith<$Res>? get account { | ||||
|     if (_self.account == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnAccountCopyWith<$Res>(_self.account!, (value) { | ||||
|     return _then(_self.copyWith(account: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnVerificationMarkCopyWith<$Res>? get verification { | ||||
|     if (_self.verification == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) { | ||||
|     return _then(_self.copyWith(verification: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _SnPublisher implements SnPublisher { | ||||
|   const _SnPublisher({this.id = '', this.type = 0, this.name = '', this.nick = '', this.bio = '', this.picture, this.background, this.account, this.accountId, this.createdAt = null, this.updatedAt = null, this.deletedAt, this.realmId, this.verification}); | ||||
|   factory _SnPublisher.fromJson(Map<String, dynamic> json) => _$SnPublisherFromJson(json); | ||||
|  | ||||
| @override@JsonKey() final  String id; | ||||
| @override@JsonKey() final  int type; | ||||
| @override@JsonKey() final  String name; | ||||
| @override@JsonKey() final  String nick; | ||||
| @override@JsonKey() final  String bio; | ||||
| @override final  SnCloudFile? picture; | ||||
| @override final  SnCloudFile? background; | ||||
| @override final  SnAccount? account; | ||||
| @override final  String? accountId; | ||||
| @override@JsonKey() final  DateTime? createdAt; | ||||
| @override@JsonKey() final  DateTime? updatedAt; | ||||
| @override final  DateTime? deletedAt; | ||||
| @override final  String? realmId; | ||||
| @override final  SnVerificationMark? verification; | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$SnPublisherCopyWith<_SnPublisher> get copyWith => __$SnPublisherCopyWithImpl<_SnPublisher>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$SnPublisherToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.verification, verification) || other.verification == verification)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId,verification); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId, verification: $verification)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$SnPublisherCopyWith<$Res> implements $SnPublisherCopyWith<$Res> { | ||||
|   factory _$SnPublisherCopyWith(_SnPublisher value, $Res Function(_SnPublisher) _then) = __$SnPublisherCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification | ||||
| }); | ||||
|  | ||||
|  | ||||
| @override $SnCloudFileCopyWith<$Res>? get picture;@override $SnCloudFileCopyWith<$Res>? get background;@override $SnAccountCopyWith<$Res>? get account;@override $SnVerificationMarkCopyWith<$Res>? get verification; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$SnPublisherCopyWithImpl<$Res> | ||||
|     implements _$SnPublisherCopyWith<$Res> { | ||||
|   __$SnPublisherCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _SnPublisher _self; | ||||
|   final $Res Function(_SnPublisher) _then; | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { | ||||
|   return _then(_SnPublisher( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||
| as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||
| as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | ||||
| as String,bio: null == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable | ||||
| as String,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable | ||||
| as SnAccount?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable | ||||
| as SnVerificationMark?, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get picture { | ||||
|     if (_self.picture == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.picture!, (value) { | ||||
|     return _then(_self.copyWith(picture: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get background { | ||||
|     if (_self.background == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.background!, (value) { | ||||
|     return _then(_self.copyWith(background: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnAccountCopyWith<$Res>? get account { | ||||
|     if (_self.account == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnAccountCopyWith<$Res>(_self.account!, (value) { | ||||
|     return _then(_self.copyWith(account: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnVerificationMarkCopyWith<$Res>? get verification { | ||||
|     if (_self.verification == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) { | ||||
|     return _then(_self.copyWith(verification: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$SnPublisherStats { | ||||
|  | ||||
|   | ||||
| @@ -48,10 +48,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost( | ||||
|           ?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>)) | ||||
|           .toList() ?? | ||||
|       const [], | ||||
|   publisher: | ||||
|       json['publisher'] == null | ||||
|           ? const SnPublisher() | ||||
|           : SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>), | ||||
|   publisher: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>), | ||||
|   reactionsCount: | ||||
|       (json['reactions_count'] as Map<String, dynamic>?)?.map( | ||||
|         (k, e) => MapEntry(k, (e as num).toInt()), | ||||
| @@ -119,64 +116,6 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{ | ||||
|   'is_truncated': instance.isTruncated, | ||||
| }; | ||||
|  | ||||
| _SnPublisher _$SnPublisherFromJson(Map<String, dynamic> json) => _SnPublisher( | ||||
|   id: json['id'] as String? ?? '', | ||||
|   type: (json['type'] as num?)?.toInt() ?? 0, | ||||
|   name: json['name'] as String? ?? '', | ||||
|   nick: json['nick'] as String? ?? '', | ||||
|   bio: json['bio'] as String? ?? '', | ||||
|   picture: | ||||
|       json['picture'] == null | ||||
|           ? null | ||||
|           : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), | ||||
|   background: | ||||
|       json['background'] == null | ||||
|           ? null | ||||
|           : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>), | ||||
|   account: | ||||
|       json['account'] == null | ||||
|           ? null | ||||
|           : SnAccount.fromJson(json['account'] as Map<String, dynamic>), | ||||
|   accountId: json['account_id'] as String?, | ||||
|   createdAt: | ||||
|       json['created_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['created_at'] as String), | ||||
|   updatedAt: | ||||
|       json['updated_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['updated_at'] as String), | ||||
|   deletedAt: | ||||
|       json['deleted_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['deleted_at'] as String), | ||||
|   realmId: json['realm_id'] as String?, | ||||
|   verification: | ||||
|       json['verification'] == null | ||||
|           ? null | ||||
|           : SnVerificationMark.fromJson( | ||||
|             json['verification'] as Map<String, dynamic>, | ||||
|           ), | ||||
| ); | ||||
|  | ||||
| Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'type': instance.type, | ||||
|       'name': instance.name, | ||||
|       'nick': instance.nick, | ||||
|       'bio': instance.bio, | ||||
|       'picture': instance.picture?.toJson(), | ||||
|       'background': instance.background?.toJson(), | ||||
|       'account': instance.account?.toJson(), | ||||
|       'account_id': instance.accountId, | ||||
|       'created_at': instance.createdAt?.toIso8601String(), | ||||
|       'updated_at': instance.updatedAt?.toIso8601String(), | ||||
|       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||
|       'realm_id': instance.realmId, | ||||
|       'verification': instance.verification?.toJson(), | ||||
|     }; | ||||
|  | ||||
| _SnPublisherStats _$SnPublisherStatsFromJson(Map<String, dynamic> json) => | ||||
|     _SnPublisherStats( | ||||
|       postsCreated: (json['posts_created'] as num).toInt(), | ||||
|   | ||||
							
								
								
									
										47
									
								
								lib/models/publisher.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lib/models/publisher.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
| import 'package:island/models/file.dart'; | ||||
| import 'package:island/models/user.dart'; | ||||
|  | ||||
| part 'publisher.freezed.dart'; | ||||
| part 'publisher.g.dart'; | ||||
|  | ||||
| @freezed | ||||
| sealed class SnPublisher with _$SnPublisher { | ||||
|   const factory SnPublisher({ | ||||
|     @Default('') String id, | ||||
|     @Default(0) int type, | ||||
|     @Default('') String name, | ||||
|     @Default('') String nick, | ||||
|     @Default('') String bio, | ||||
|     SnCloudFile? picture, | ||||
|     SnCloudFile? background, | ||||
|     SnAccount? account, | ||||
|     String? accountId, | ||||
|     @Default(null) DateTime? createdAt, | ||||
|     @Default(null) DateTime? updatedAt, | ||||
|     DateTime? deletedAt, | ||||
|     String? realmId, | ||||
|     SnVerificationMark? verification, | ||||
|   }) = _SnPublisher; | ||||
|  | ||||
|   factory SnPublisher.fromJson(Map<String, dynamic> json) => | ||||
|       _$SnPublisherFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| sealed class SnPublisherMember with _$SnPublisherMember { | ||||
|   const factory SnPublisherMember({ | ||||
|     required String publisherId, | ||||
|     required SnPublisher? publisher, | ||||
|     required String accountId, | ||||
|     required SnAccount? account, | ||||
|     required int role, | ||||
|     required DateTime? joinedAt, | ||||
|     required DateTime createdAt, | ||||
|     required DateTime updatedAt, | ||||
|     required DateTime? deletedAt, | ||||
|   }) = _SnPublisherMember; | ||||
|  | ||||
|   factory SnPublisherMember.fromJson(Map<String, dynamic> json) => | ||||
|       _$SnPublisherMemberFromJson(json); | ||||
| } | ||||
							
								
								
									
										488
									
								
								lib/models/publisher.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										488
									
								
								lib/models/publisher.freezed.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,488 @@ | ||||
| // dart format width=80 | ||||
| // coverage:ignore-file | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark | ||||
|  | ||||
| part of 'publisher.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // FreezedGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| // dart format off | ||||
| T _$identity<T>(T value) => value; | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$SnPublisher { | ||||
|  | ||||
|  String get id; int get type; String get name; String get nick; String get bio; SnCloudFile? get picture; SnCloudFile? get background; SnAccount? get account; String? get accountId; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; String? get realmId; SnVerificationMark? get verification; | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnPublisherCopyWith<SnPublisher> get copyWith => _$SnPublisherCopyWithImpl<SnPublisher>(this as SnPublisher, _$identity); | ||||
|  | ||||
|   /// Serializes this SnPublisher to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.verification, verification) || other.verification == verification)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId,verification); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId, verification: $verification)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $SnPublisherCopyWith<$Res>  { | ||||
|   factory $SnPublisherCopyWith(SnPublisher value, $Res Function(SnPublisher) _then) = _$SnPublisherCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification | ||||
| }); | ||||
|  | ||||
|  | ||||
| $SnCloudFileCopyWith<$Res>? get picture;$SnCloudFileCopyWith<$Res>? get background;$SnAccountCopyWith<$Res>? get account;$SnVerificationMarkCopyWith<$Res>? get verification; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$SnPublisherCopyWithImpl<$Res> | ||||
|     implements $SnPublisherCopyWith<$Res> { | ||||
|   _$SnPublisherCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final SnPublisher _self; | ||||
|   final $Res Function(SnPublisher) _then; | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { | ||||
|   return _then(_self.copyWith( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||
| as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||
| as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | ||||
| as String,bio: null == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable | ||||
| as String,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable | ||||
| as SnAccount?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable | ||||
| as SnVerificationMark?, | ||||
|   )); | ||||
| } | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get picture { | ||||
|     if (_self.picture == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.picture!, (value) { | ||||
|     return _then(_self.copyWith(picture: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get background { | ||||
|     if (_self.background == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.background!, (value) { | ||||
|     return _then(_self.copyWith(background: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnAccountCopyWith<$Res>? get account { | ||||
|     if (_self.account == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnAccountCopyWith<$Res>(_self.account!, (value) { | ||||
|     return _then(_self.copyWith(account: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnVerificationMarkCopyWith<$Res>? get verification { | ||||
|     if (_self.verification == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) { | ||||
|     return _then(_self.copyWith(verification: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _SnPublisher implements SnPublisher { | ||||
|   const _SnPublisher({this.id = '', this.type = 0, this.name = '', this.nick = '', this.bio = '', this.picture, this.background, this.account, this.accountId, this.createdAt = null, this.updatedAt = null, this.deletedAt, this.realmId, this.verification}); | ||||
|   factory _SnPublisher.fromJson(Map<String, dynamic> json) => _$SnPublisherFromJson(json); | ||||
|  | ||||
| @override@JsonKey() final  String id; | ||||
| @override@JsonKey() final  int type; | ||||
| @override@JsonKey() final  String name; | ||||
| @override@JsonKey() final  String nick; | ||||
| @override@JsonKey() final  String bio; | ||||
| @override final  SnCloudFile? picture; | ||||
| @override final  SnCloudFile? background; | ||||
| @override final  SnAccount? account; | ||||
| @override final  String? accountId; | ||||
| @override@JsonKey() final  DateTime? createdAt; | ||||
| @override@JsonKey() final  DateTime? updatedAt; | ||||
| @override final  DateTime? deletedAt; | ||||
| @override final  String? realmId; | ||||
| @override final  SnVerificationMark? verification; | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$SnPublisherCopyWith<_SnPublisher> get copyWith => __$SnPublisherCopyWithImpl<_SnPublisher>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$SnPublisherToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublisher&&(identical(other.id, id) || other.id == id)&&(identical(other.type, type) || other.type == type)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.account, account) || other.account == account)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.verification, verification) || other.verification == verification)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,type,name,nick,bio,picture,background,account,accountId,createdAt,updatedAt,deletedAt,realmId,verification); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPublisher(id: $id, type: $type, name: $name, nick: $nick, bio: $bio, picture: $picture, background: $background, account: $account, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, realmId: $realmId, verification: $verification)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$SnPublisherCopyWith<$Res> implements $SnPublisherCopyWith<$Res> { | ||||
|   factory _$SnPublisherCopyWith(_SnPublisher value, $Res Function(_SnPublisher) _then) = __$SnPublisherCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification | ||||
| }); | ||||
|  | ||||
|  | ||||
| @override $SnCloudFileCopyWith<$Res>? get picture;@override $SnCloudFileCopyWith<$Res>? get background;@override $SnAccountCopyWith<$Res>? get account;@override $SnVerificationMarkCopyWith<$Res>? get verification; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$SnPublisherCopyWithImpl<$Res> | ||||
|     implements _$SnPublisherCopyWith<$Res> { | ||||
|   __$SnPublisherCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _SnPublisher _self; | ||||
|   final $Res Function(_SnPublisher) _then; | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { | ||||
|   return _then(_SnPublisher( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||
| as int,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||
| as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | ||||
| as String,bio: null == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable | ||||
| as String,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||
| as SnCloudFile?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable | ||||
| as SnAccount?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable | ||||
| as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable | ||||
| as SnVerificationMark?, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| /// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get picture { | ||||
|     if (_self.picture == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.picture!, (value) { | ||||
|     return _then(_self.copyWith(picture: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnCloudFileCopyWith<$Res>? get background { | ||||
|     if (_self.background == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnCloudFileCopyWith<$Res>(_self.background!, (value) { | ||||
|     return _then(_self.copyWith(background: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnAccountCopyWith<$Res>? get account { | ||||
|     if (_self.account == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnAccountCopyWith<$Res>(_self.account!, (value) { | ||||
|     return _then(_self.copyWith(account: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisher | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnVerificationMarkCopyWith<$Res>? get verification { | ||||
|     if (_self.verification == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnVerificationMarkCopyWith<$Res>(_self.verification!, (value) { | ||||
|     return _then(_self.copyWith(verification: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$SnPublisherMember { | ||||
|  | ||||
|  String get publisherId; SnPublisher? get publisher; String get accountId; SnAccount? get account; int get role; DateTime? get joinedAt; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||
| /// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnPublisherMemberCopyWith<SnPublisherMember> get copyWith => _$SnPublisherMemberCopyWithImpl<SnPublisherMember>(this as SnPublisherMember, _$identity); | ||||
|  | ||||
|   /// Serializes this SnPublisherMember to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPublisherMember&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,publisherId,publisher,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPublisherMember(publisherId: $publisherId, publisher: $publisher, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $SnPublisherMemberCopyWith<$Res>  { | ||||
|   factory $SnPublisherMemberCopyWith(SnPublisherMember value, $Res Function(SnPublisherMember) _then) = _$SnPublisherMemberCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String publisherId, SnPublisher? publisher, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||
| }); | ||||
|  | ||||
|  | ||||
| $SnPublisherCopyWith<$Res>? get publisher;$SnAccountCopyWith<$Res>? get account; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$SnPublisherMemberCopyWithImpl<$Res> | ||||
|     implements $SnPublisherMemberCopyWith<$Res> { | ||||
|   _$SnPublisherMemberCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final SnPublisherMember _self; | ||||
|   final $Res Function(SnPublisherMember) _then; | ||||
|  | ||||
| /// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? publisherId = null,Object? publisher = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||
|   return _then(_self.copyWith( | ||||
| publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable | ||||
| as String,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable | ||||
| as SnPublisher?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable | ||||
| as SnAccount?,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable | ||||
| as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?, | ||||
|   )); | ||||
| } | ||||
| /// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnPublisherCopyWith<$Res>? get publisher { | ||||
|     if (_self.publisher == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) { | ||||
|     return _then(_self.copyWith(publisher: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnAccountCopyWith<$Res>? get account { | ||||
|     if (_self.account == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnAccountCopyWith<$Res>(_self.account!, (value) { | ||||
|     return _then(_self.copyWith(account: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _SnPublisherMember implements SnPublisherMember { | ||||
|   const _SnPublisherMember({required this.publisherId, required this.publisher, required this.accountId, required this.account, required this.role, required this.joinedAt, required this.createdAt, required this.updatedAt, required this.deletedAt}); | ||||
|   factory _SnPublisherMember.fromJson(Map<String, dynamic> json) => _$SnPublisherMemberFromJson(json); | ||||
|  | ||||
| @override final  String publisherId; | ||||
| @override final  SnPublisher? publisher; | ||||
| @override final  String accountId; | ||||
| @override final  SnAccount? account; | ||||
| @override final  int role; | ||||
| @override final  DateTime? joinedAt; | ||||
| @override final  DateTime createdAt; | ||||
| @override final  DateTime updatedAt; | ||||
| @override final  DateTime? deletedAt; | ||||
|  | ||||
| /// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$SnPublisherMemberCopyWith<_SnPublisherMember> get copyWith => __$SnPublisherMemberCopyWithImpl<_SnPublisherMember>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$SnPublisherMemberToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPublisherMember&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,publisherId,publisher,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPublisherMember(publisherId: $publisherId, publisher: $publisher, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$SnPublisherMemberCopyWith<$Res> implements $SnPublisherMemberCopyWith<$Res> { | ||||
|   factory _$SnPublisherMemberCopyWith(_SnPublisherMember value, $Res Function(_SnPublisherMember) _then) = __$SnPublisherMemberCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String publisherId, SnPublisher? publisher, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||
| }); | ||||
|  | ||||
|  | ||||
| @override $SnPublisherCopyWith<$Res>? get publisher;@override $SnAccountCopyWith<$Res>? get account; | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$SnPublisherMemberCopyWithImpl<$Res> | ||||
|     implements _$SnPublisherMemberCopyWith<$Res> { | ||||
|   __$SnPublisherMemberCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _SnPublisherMember _self; | ||||
|   final $Res Function(_SnPublisherMember) _then; | ||||
|  | ||||
| /// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? publisherId = null,Object? publisher = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||
|   return _then(_SnPublisherMember( | ||||
| publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable | ||||
| as String,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable | ||||
| as SnPublisher?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable | ||||
| as SnAccount?,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable | ||||
| as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| /// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnPublisherCopyWith<$Res>? get publisher { | ||||
|     if (_self.publisher == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) { | ||||
|     return _then(_self.copyWith(publisher: value)); | ||||
|   }); | ||||
| }/// Create a copy of SnPublisherMember | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnAccountCopyWith<$Res>? get account { | ||||
|     if (_self.account == null) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return $SnAccountCopyWith<$Res>(_self.account!, (value) { | ||||
|     return _then(_self.copyWith(account: value)); | ||||
|   }); | ||||
| } | ||||
| } | ||||
|  | ||||
| // dart format on | ||||
							
								
								
									
										103
									
								
								lib/models/publisher.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								lib/models/publisher.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'publisher.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // JsonSerializableGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| _SnPublisher _$SnPublisherFromJson(Map<String, dynamic> json) => _SnPublisher( | ||||
|   id: json['id'] as String? ?? '', | ||||
|   type: (json['type'] as num?)?.toInt() ?? 0, | ||||
|   name: json['name'] as String? ?? '', | ||||
|   nick: json['nick'] as String? ?? '', | ||||
|   bio: json['bio'] as String? ?? '', | ||||
|   picture: | ||||
|       json['picture'] == null | ||||
|           ? null | ||||
|           : SnCloudFile.fromJson(json['picture'] as Map<String, dynamic>), | ||||
|   background: | ||||
|       json['background'] == null | ||||
|           ? null | ||||
|           : SnCloudFile.fromJson(json['background'] as Map<String, dynamic>), | ||||
|   account: | ||||
|       json['account'] == null | ||||
|           ? null | ||||
|           : SnAccount.fromJson(json['account'] as Map<String, dynamic>), | ||||
|   accountId: json['account_id'] as String?, | ||||
|   createdAt: | ||||
|       json['created_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['created_at'] as String), | ||||
|   updatedAt: | ||||
|       json['updated_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['updated_at'] as String), | ||||
|   deletedAt: | ||||
|       json['deleted_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['deleted_at'] as String), | ||||
|   realmId: json['realm_id'] as String?, | ||||
|   verification: | ||||
|       json['verification'] == null | ||||
|           ? null | ||||
|           : SnVerificationMark.fromJson( | ||||
|             json['verification'] as Map<String, dynamic>, | ||||
|           ), | ||||
| ); | ||||
|  | ||||
| Map<String, dynamic> _$SnPublisherToJson(_SnPublisher instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'type': instance.type, | ||||
|       'name': instance.name, | ||||
|       'nick': instance.nick, | ||||
|       'bio': instance.bio, | ||||
|       'picture': instance.picture?.toJson(), | ||||
|       'background': instance.background?.toJson(), | ||||
|       'account': instance.account?.toJson(), | ||||
|       'account_id': instance.accountId, | ||||
|       'created_at': instance.createdAt?.toIso8601String(), | ||||
|       'updated_at': instance.updatedAt?.toIso8601String(), | ||||
|       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||
|       'realm_id': instance.realmId, | ||||
|       'verification': instance.verification?.toJson(), | ||||
|     }; | ||||
|  | ||||
| _SnPublisherMember _$SnPublisherMemberFromJson(Map<String, dynamic> json) => | ||||
|     _SnPublisherMember( | ||||
|       publisherId: json['publisher_id'] as String, | ||||
|       publisher: | ||||
|           json['publisher'] == null | ||||
|               ? null | ||||
|               : SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>), | ||||
|       accountId: json['account_id'] as String, | ||||
|       account: | ||||
|           json['account'] == null | ||||
|               ? null | ||||
|               : SnAccount.fromJson(json['account'] as Map<String, dynamic>), | ||||
|       role: (json['role'] as num).toInt(), | ||||
|       joinedAt: | ||||
|           json['joined_at'] == null | ||||
|               ? null | ||||
|               : DateTime.parse(json['joined_at'] as String), | ||||
|       createdAt: DateTime.parse(json['created_at'] as String), | ||||
|       updatedAt: DateTime.parse(json['updated_at'] as String), | ||||
|       deletedAt: | ||||
|           json['deleted_at'] == null | ||||
|               ? null | ||||
|               : DateTime.parse(json['deleted_at'] as String), | ||||
|     ); | ||||
|  | ||||
| Map<String, dynamic> _$SnPublisherMemberToJson(_SnPublisherMember instance) => | ||||
|     <String, dynamic>{ | ||||
|       'publisher_id': instance.publisherId, | ||||
|       'publisher': instance.publisher?.toJson(), | ||||
|       'account_id': instance.accountId, | ||||
|       'account': instance.account?.toJson(), | ||||
|       'role': instance.role, | ||||
|       'joined_at': instance.joinedAt?.toIso8601String(), | ||||
|       'created_at': instance.createdAt.toIso8601String(), | ||||
|       'updated_at': instance.updatedAt.toIso8601String(), | ||||
|       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||
|     }; | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
| import 'package:island/models/file.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
|  | ||||
| part 'sticker.freezed.dart'; | ||||
| part 'sticker.g.dart'; | ||||
|   | ||||
| @@ -11,11 +11,6 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> { | ||||
|  | ||||
|   UserInfoNotifier(this._ref) : super(const AsyncValue.data(null)); | ||||
|  | ||||
|   Future<String?> getAccessToken() async { | ||||
|     final prefs = _ref.read(sharedPreferencesProvider); | ||||
|     return prefs.getString(kTokenPairStoreKey); | ||||
|   } | ||||
|  | ||||
|   Future<void> fetchUser() async { | ||||
|     try { | ||||
|       final client = _ref.read(apiClientProvider); | ||||
|   | ||||
							
								
								
									
										120
									
								
								lib/route.dart
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								lib/route.dart
									
									
									
									
									
								
							| @@ -1,6 +1,10 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/screens/developers/apps.dart'; | ||||
| import 'package:island/screens/developers/edit_app.dart'; | ||||
| import 'package:island/screens/developers/new_app.dart'; | ||||
| import 'package:island/screens/developers/hub.dart'; | ||||
| import 'package:island/widgets/app_wrapper.dart'; | ||||
| import 'package:island/screens/tabs.dart'; | ||||
|  | ||||
| @@ -79,33 +83,37 @@ final routerProvider = Provider<GoRouter>((ref) { | ||||
|               return EventCalanderScreen(name: name); | ||||
|             }, | ||||
|           ), | ||||
|           GoRoute( | ||||
|             path: '/creators', | ||||
|             builder: (context, state) => const CreatorHubScreen(), | ||||
|           ShellRoute( | ||||
|             builder: | ||||
|                 (context, state, child) => CreatorHubShellScreen(child: child), | ||||
|             routes: [ | ||||
|               GoRoute( | ||||
|                 path: ':name/posts', | ||||
|                 path: '/creators', | ||||
|                 builder: (context, state) => const CreatorHubScreen(), | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: '/creators/:name/posts', | ||||
|                 builder: (context, state) { | ||||
|                   final name = state.pathParameters['name']!; | ||||
|                   return CreatorPostListScreen(pubName: name); | ||||
|                 }, | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: ':name/stickers', | ||||
|                 path: '/creators/:name/stickers', | ||||
|                 builder: (context, state) { | ||||
|                   final name = state.pathParameters['name']!; | ||||
|                   return StickersScreen(pubName: name); | ||||
|                 }, | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: ':name/stickers/new', | ||||
|                 path: '/creators/:name/stickers/new', | ||||
|                 builder: (context, state) { | ||||
|                   final name = state.pathParameters['name']!; | ||||
|                   return NewStickerPacksScreen(pubName: name); | ||||
|                 }, | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: ':name/stickers/:packId/edit', | ||||
|                 path: '/creators/:name/stickers/:packId/edit', | ||||
|                 builder: (context, state) { | ||||
|                   final name = state.pathParameters['name']!; | ||||
|                   final packId = state.pathParameters['packId']!; | ||||
| @@ -113,7 +121,7 @@ final routerProvider = Provider<GoRouter>((ref) { | ||||
|                 }, | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: ':name/stickers/:packId', | ||||
|                 path: '/creators/:name/stickers/:packId', | ||||
|                 builder: (context, state) { | ||||
|                   final name = state.pathParameters['name']!; | ||||
|                   final packId = state.pathParameters['packId']!; | ||||
| @@ -121,14 +129,14 @@ final routerProvider = Provider<GoRouter>((ref) { | ||||
|                 }, | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: ':name/stickers/:packId/new', | ||||
|                 path: '/creators/:name/stickers/:packId/new', | ||||
|                 builder: (context, state) { | ||||
|                   final packId = state.pathParameters['packId']!; | ||||
|                   return NewStickersScreen(packId: packId); | ||||
|                 }, | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: ':name/stickers/:packId/:id/edit', | ||||
|                 path: '/creators/:name/stickers/:packId/:id/edit', | ||||
|                 builder: (context, state) { | ||||
|                   final packId = state.pathParameters['packId']!; | ||||
|                   final id = state.pathParameters['id']!; | ||||
| @@ -136,11 +144,11 @@ final routerProvider = Provider<GoRouter>((ref) { | ||||
|                 }, | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: 'new', | ||||
|                 path: '/creators/new', | ||||
|                 builder: (context, state) => const NewPublisherScreen(), | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: ':name/edit', | ||||
|                 path: '/creators/:name/edit', | ||||
|                 builder: (context, state) { | ||||
|                   final name = state.pathParameters['name']!; | ||||
|                   return EditPublisherScreen(name: name); | ||||
| @@ -148,6 +156,36 @@ final routerProvider = Provider<GoRouter>((ref) { | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|           ShellRoute( | ||||
|             builder: | ||||
|                 (context, state, child) => | ||||
|                     DeveloperHubShellScreen(child: child), | ||||
|             routes: [ | ||||
|               GoRoute( | ||||
|                 path: '/developers', | ||||
|                 builder: (context, state) => const DeveloperHubScreen(), | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: '/developers/:name/apps', | ||||
|                 builder: (context, state) => CustomAppsScreen( | ||||
|                   publisherName: state.pathParameters['name']!, | ||||
|                 ), | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: '/developers/:name/apps/new', | ||||
|                 builder: (context, state) => NewCustomAppScreen( | ||||
|                   publisherName: state.pathParameters['name']!, | ||||
|                 ), | ||||
|               ), | ||||
|               GoRoute( | ||||
|                 path: '/developers/:name/apps/:id', | ||||
|                 builder: (context, state) => EditAppScreen( | ||||
|                   publisherName: state.pathParameters['name']!, | ||||
|                   id: state.pathParameters['id']!, | ||||
|                 ), | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|  | ||||
|           // Auth routes | ||||
|           GoRoute( | ||||
| @@ -173,56 +211,64 @@ final routerProvider = Provider<GoRouter>((ref) { | ||||
|             }, | ||||
|             routes: [ | ||||
|               // Explore tab | ||||
|               GoRoute( | ||||
|                 path: '/', | ||||
|                 builder: (context, state) => const ExploreScreen(), | ||||
|               ShellRoute( | ||||
|                 builder: | ||||
|                     (context, state, child) => ExploreShellScreen(child: child), | ||||
|                 routes: [ | ||||
|                   GoRoute( | ||||
|                     path: 'posts/:id', | ||||
|                     path: '/', | ||||
|                     builder: (context, state) => const ExploreScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: '/posts/:id', | ||||
|                     builder: (context, state) { | ||||
|                       final id = state.pathParameters['id']!; | ||||
|                       return PostDetailScreen(id: id); | ||||
|                     }, | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: 'publishers/:name', | ||||
|                     path: '/publishers/:name', | ||||
|                     builder: (context, state) { | ||||
|                       final name = state.pathParameters['name']!; | ||||
|                       return PublisherProfileScreen(name: name); | ||||
|                     }, | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: 'discovery/realms', | ||||
|                     path: '/discovery/realms', | ||||
|                     builder: (context, state) => const DiscoveryRealmsScreen(), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|  | ||||
|               // Chat tab | ||||
|               GoRoute( | ||||
|                 path: '/chat', | ||||
|                 builder: (context, state) => const ChatListScreen(), | ||||
|               ShellRoute( | ||||
|                 builder: | ||||
|                     (context, state, child) => ChatShellScreen(child: child), | ||||
|                 routes: [ | ||||
|                   GoRoute( | ||||
|                     path: 'new', | ||||
|                     path: '/chat', | ||||
|                     builder: (context, state) => const ChatListScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: '/chat/new', | ||||
|                     builder: (context, state) => const NewChatScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: ':id', | ||||
|                     path: '/chat/:id', | ||||
|                     builder: (context, state) { | ||||
|                       final id = state.pathParameters['id']!; | ||||
|                       return ChatRoomScreen(id: id); | ||||
|                     }, | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: ':id/edit', | ||||
|                     path: '/chat/:id/edit', | ||||
|                     builder: (context, state) { | ||||
|                       final id = state.pathParameters['id']!; | ||||
|                       return EditChatScreen(id: id); | ||||
|                     }, | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: ':id/detail', | ||||
|                     path: '/chat/:id/detail', | ||||
|                     builder: (context, state) { | ||||
|                       final id = state.pathParameters['id']!; | ||||
|                       return ChatDetailScreen(id: id); | ||||
| @@ -258,39 +304,43 @@ final routerProvider = Provider<GoRouter>((ref) { | ||||
|               ), | ||||
|  | ||||
|               // Account tab | ||||
|               GoRoute( | ||||
|                 path: '/account', | ||||
|                 builder: (context, state) => const AccountScreen(), | ||||
|               ShellRoute( | ||||
|                 builder: | ||||
|                     (context, state, child) => AccountShellScreen(child: child), | ||||
|                 routes: [ | ||||
|                   GoRoute( | ||||
|                     path: 'notifications', | ||||
|                     path: '/account', | ||||
|                     builder: (context, state) => const AccountScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: '/account/notifications', | ||||
|                     builder: (context, state) => const NotificationScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: 'wallet', | ||||
|                     path: '/account/wallet', | ||||
|                     builder: (context, state) => const WalletScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: 'relationships', | ||||
|                     path: '/account/relationships', | ||||
|                     builder: (context, state) => const RelationshipScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: ':name', | ||||
|                     path: '/account/:name', | ||||
|                     builder: (context, state) { | ||||
|                       final name = state.pathParameters['name']!; | ||||
|                       return AccountProfileScreen(name: name); | ||||
|                     }, | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: 'me/update', | ||||
|                     path: '/account/me/update', | ||||
|                     builder: (context, state) => const UpdateProfileScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: 'me/leveling', | ||||
|                     path: '/account/me/leveling', | ||||
|                     builder: (context, state) => const LevelingScreen(), | ||||
|                   ), | ||||
|                   GoRoute( | ||||
|                     path: 'settings', | ||||
|                     path: '/account/settings', | ||||
|                     builder: (context, state) => const AccountSettingsScreen(), | ||||
|                   ), | ||||
|                 ], | ||||
|   | ||||
| @@ -143,7 +143,7 @@ class AccountScreen extends HookConsumerWidget { | ||||
|                 progress: user.value!.profile.levelingProgress, | ||||
|               ), | ||||
|               onTap: () { | ||||
|                 context.push('/account/leveling'); | ||||
|                 context.push('/account/me/leveling'); | ||||
|               }, | ||||
|             ).padding(horizontal: 12), | ||||
|             Row( | ||||
| @@ -178,7 +178,9 @@ class AccountScreen extends HookConsumerWidget { | ||||
|                           Text('developerPortalDescription').tr(), | ||||
|                         ], | ||||
|                       ).padding(horizontal: 16, vertical: 12), | ||||
|                       onTap: () {}, | ||||
|                       onTap: () { | ||||
|                         context.push('/developers'); | ||||
|                       }, | ||||
|                     ), | ||||
|                   ).height(140), | ||||
|                 ), | ||||
| @@ -210,7 +212,7 @@ class AccountScreen extends HookConsumerWidget { | ||||
|               contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||
|               title: Text('wallet').tr(), | ||||
|               onTap: () { | ||||
|                 context.push('/wallet'); | ||||
|                 context.push('/account/wallet'); | ||||
|               }, | ||||
|             ), | ||||
|             ListTile( | ||||
|   | ||||
| @@ -53,17 +53,21 @@ Future<List<SnAccountBadge>> accountBadges(Ref ref, String uname) async { | ||||
|  | ||||
| @riverpod | ||||
| Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async { | ||||
|   final account = await ref.watch(accountProvider(uname).future); | ||||
|   if (account.profile.background == null) return null; | ||||
|   final palette = await PaletteGenerator.fromImageProvider( | ||||
|     CloudImageWidget.provider( | ||||
|       fileId: account.profile.background!.id, | ||||
|       serverUrl: ref.watch(serverUrlProvider), | ||||
|     ), | ||||
|   ); | ||||
|   final dominantColor = palette.dominantColor?.color; | ||||
|   if (dominantColor == null) return null; | ||||
|   return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; | ||||
|   try { | ||||
|     final account = await ref.watch(accountProvider(uname).future); | ||||
|     if (account.profile.background == null) return null; | ||||
|     final palette = await PaletteGenerator.fromImageProvider( | ||||
|       CloudImageWidget.provider( | ||||
|         fileId: account.profile.background!.id, | ||||
|         serverUrl: ref.watch(serverUrlProvider), | ||||
|       ), | ||||
|     ); | ||||
|     final dominantColor = palette.dominantColor?.color; | ||||
|     if (dominantColor == null) return null; | ||||
|     return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; | ||||
|   } catch (_) { | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @riverpod | ||||
|   | ||||
| @@ -268,7 +268,7 @@ class _AccountBadgesProviderElement | ||||
| } | ||||
|  | ||||
| String _$accountAppbarForcegroundColorHash() => | ||||
|     r'f654a7a5594eda1500906e9ad023c22772257a9b'; | ||||
|     r'8ee0cae10817b77fb09548a482f5247662b4374c'; | ||||
|  | ||||
| /// See also [accountAppbarForcegroundColor]. | ||||
| @ProviderFor(accountAppbarForcegroundColor) | ||||
|   | ||||
| @@ -676,17 +676,36 @@ class EditChatScreen extends HookConsumerWidget { | ||||
|                       (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 CheckboxListTile( | ||||
|                   title: const Text('isPublic').tr(), | ||||
|                   subtitle: const Text('isPublicHint').tr(), | ||||
|                   value: isPublic.value, | ||||
|                   onChanged: (value) => isPublic.value = value ?? false, | ||||
|                 ), | ||||
|                 CheckboxListTile( | ||||
|                   title: const Text('isCommunity').tr(), | ||||
|                   subtitle: const Text('isCommunityHint').tr(), | ||||
|                   value: isCommunity.value, | ||||
|                   onChanged: (value) => isCommunity.value = value ?? false, | ||||
|                 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( | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:dropdown_button2/dropdown_button2.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| @@ -6,14 +7,19 @@ import 'package:flutter_hooks/flutter_hooks.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/screens/creators/publishers.dart'; | ||||
| import 'package:island/services/responsive.dart'; | ||||
| import 'package:island/widgets/account/account_picker.dart'; | ||||
| import 'package:island/widgets/alert.dart'; | ||||
| import 'package:island/widgets/app_scaffold.dart'; | ||||
| import 'package:island/widgets/content/cloud_files.dart'; | ||||
| import 'package:island/widgets/content/sheet.dart'; | ||||
| import 'package:island/widgets/response.dart'; | ||||
| import 'package:material_symbols_icons/symbols.dart'; | ||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||
| import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||
| import 'package:styled_widget/styled_widget.dart'; | ||||
|  | ||||
| part 'hub.g.dart'; | ||||
| @@ -26,6 +32,65 @@ Future<SnPublisherStats?> publisherStats(Ref ref, String? uname) async { | ||||
|   return SnPublisherStats.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| @riverpod | ||||
| Future<SnPublisherMember?> publisherIdentity(Ref ref, String uname) async { | ||||
|   try { | ||||
|     final apiClient = ref.watch(apiClientProvider); | ||||
|     final response = await apiClient.get('/publishers/$uname/members/me'); | ||||
|     return SnPublisherMember.fromJson(response.data); | ||||
|   } catch (err) { | ||||
|     if (err is DioException && err.response?.statusCode == 404) { | ||||
|       return null; // No identity found, user is not a member | ||||
|     } | ||||
|     rethrow; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @riverpod | ||||
| Future<List<SnPublisherMember>> publisherInvites(Ref ref) async { | ||||
|   final client = ref.watch(apiClientProvider); | ||||
|   final resp = await client.get('/publishers/invites'); | ||||
|   return resp.data | ||||
|       .map((e) => SnPublisherMember.fromJson(e)) | ||||
|       .cast<SnPublisherMember>() | ||||
|       .toList(); | ||||
| } | ||||
|  | ||||
| @riverpod | ||||
| class PublisherMemberListNotifier extends _$PublisherMemberListNotifier | ||||
|     with CursorPagingNotifierMixin<SnPublisherMember> { | ||||
|   static const int _pageSize = 20; | ||||
|  | ||||
|   @override | ||||
|   Future<CursorPagingData<SnPublisherMember>> build(String uname) async { | ||||
|     return fetch(); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<CursorPagingData<SnPublisherMember>> fetch({String? cursor}) async { | ||||
|     final apiClient = ref.read(apiClientProvider); | ||||
|     final offset = cursor != null ? int.parse(cursor) : 0; | ||||
|  | ||||
|     final response = await apiClient.get( | ||||
|       '/publishers/$uname/members', | ||||
|       queryParameters: {'offset': offset, 'take': _pageSize}, | ||||
|     ); | ||||
|  | ||||
|     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||
|     final List<dynamic> data = response.data; | ||||
|     final members = data.map((e) => SnPublisherMember.fromJson(e)).toList(); | ||||
|  | ||||
|     final hasMore = offset + members.length < total; | ||||
|     final nextCursor = hasMore ? (offset + members.length).toString() : null; | ||||
|  | ||||
|     return CursorPagingData( | ||||
|       items: members, | ||||
|       hasMore: hasMore, | ||||
|       nextCursor: nextCursor, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class CreatorHubShellScreen extends StatelessWidget { | ||||
|   final Widget child; | ||||
|   const CreatorHubShellScreen({super.key, required this.child}); | ||||
| @@ -58,21 +123,20 @@ class CreatorHubScreen extends HookConsumerWidget { | ||||
|     } | ||||
|  | ||||
|     final publishers = ref.watch(publishersManagedProvider); | ||||
|     final publisherInvites = ref.watch(publisherInvitesProvider); | ||||
|     final currentPublisher = useState<SnPublisher?>( | ||||
|       publishers.value?.firstOrNull, | ||||
|     ); | ||||
|  | ||||
|     void updatePublisher() { | ||||
|       context | ||||
|           .push('/creators/${currentPublisher.value!.name}/edit') | ||||
|           .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.push('/creators/${currentPublisher.value!.name}/edit').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() { | ||||
| @@ -126,6 +190,30 @@ class CreatorHubScreen extends HookConsumerWidget { | ||||
|         leading: !isWide ? const PageBackButton() : null, | ||||
|         title: Text('creatorHub').tr(), | ||||
|         actions: [ | ||||
|           IconButton( | ||||
|             icon: Badge( | ||||
|               label: Text( | ||||
|                 publisherInvites.when( | ||||
|                   data: (invites) => invites.length.toString(), | ||||
|                   error: (_, _) => '0', | ||||
|                   loading: () => '0', | ||||
|                 ), | ||||
|               ), | ||||
|               isLabelVisible: publisherInvites.when( | ||||
|                 data: (invites) => invites.isNotEmpty, | ||||
|                 error: (_, _) => false, | ||||
|                 loading: () => false, | ||||
|               ), | ||||
|               child: const Icon(Symbols.email), | ||||
|             ), | ||||
|             onPressed: () { | ||||
|               showModalBottomSheet( | ||||
|                 context: context, | ||||
|                 isScrollControlled: true, | ||||
|                 builder: (_) => const _PublisherInviteSheet(), | ||||
|               ); | ||||
|             }, | ||||
|           ), | ||||
|           DropdownButtonHideUnderline( | ||||
|             child: DropdownButton2<SnPublisher>( | ||||
|               alignment: Alignment.centerRight, | ||||
| @@ -203,7 +291,7 @@ class CreatorHubScreen extends HookConsumerWidget { | ||||
|                           ...(publishers.value?.map( | ||||
|                                 (publisher) => ListTile( | ||||
|                                   leading: ProfilePictureWidget( | ||||
|                                     fileId: publisher.picture?.id, | ||||
|                                     file: publisher.picture, | ||||
|                                   ), | ||||
|                                   title: Text(publisher.nick), | ||||
|                                   subtitle: Text('@${publisher.name}'), | ||||
| @@ -266,6 +354,26 @@ class CreatorHubScreen extends HookConsumerWidget { | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                           ListTile( | ||||
|                             minTileHeight: 48, | ||||
|                             title: Text('publisherMembers').tr(), | ||||
|                             trailing: Icon(Symbols.chevron_right), | ||||
|                             leading: const Icon(Symbols.group), | ||||
|                             contentPadding: EdgeInsets.symmetric( | ||||
|                               horizontal: 24, | ||||
|                             ), | ||||
|                             onTap: () { | ||||
|                               showModalBottomSheet( | ||||
|                                 isScrollControlled: true, | ||||
|                                 context: context, | ||||
|                                 builder: | ||||
|                                     (context) => _PublisherMemberListSheet( | ||||
|                                       publisherUname: | ||||
|                                           currentPublisher.value!.name, | ||||
|                                     ), | ||||
|                               ); | ||||
|                             }, | ||||
|                           ), | ||||
|                           Divider(height: 1).padding(vertical: 8), | ||||
|                           ListTile( | ||||
|                             minTileHeight: 48, | ||||
| @@ -393,3 +501,482 @@ class _PublisherStatsWidget extends StatelessWidget { | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class PublisherMemberState { | ||||
|   final List<SnPublisherMember> members; | ||||
|   final bool isLoading; | ||||
|   final int total; | ||||
|   final String? error; | ||||
|  | ||||
|   const PublisherMemberState({ | ||||
|     required this.members, | ||||
|     required this.isLoading, | ||||
|     required this.total, | ||||
|     this.error, | ||||
|   }); | ||||
|  | ||||
|   PublisherMemberState copyWith({ | ||||
|     List<SnPublisherMember>? members, | ||||
|     bool? isLoading, | ||||
|     int? total, | ||||
|     String? error, | ||||
|   }) { | ||||
|     return PublisherMemberState( | ||||
|       members: members ?? this.members, | ||||
|       isLoading: isLoading ?? this.isLoading, | ||||
|       total: total ?? this.total, | ||||
|       error: error ?? this.error, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| final publisherMemberStateProvider = StateNotifierProvider.family< | ||||
|   PublisherMemberNotifier, | ||||
|   PublisherMemberState, | ||||
|   String | ||||
| >((ref, publisherUname) { | ||||
|   final apiClient = ref.watch(apiClientProvider); | ||||
|   return PublisherMemberNotifier(apiClient, publisherUname); | ||||
| }); | ||||
|  | ||||
| class PublisherMemberNotifier extends StateNotifier<PublisherMemberState> { | ||||
|   final String publisherUname; | ||||
|   final Dio _apiClient; | ||||
|  | ||||
|   PublisherMemberNotifier(this._apiClient, this.publisherUname) | ||||
|     : super( | ||||
|         const PublisherMemberState(members: [], isLoading: false, total: 0), | ||||
|       ); | ||||
|  | ||||
|   Future<void> loadMore({int offset = 0, int take = 20}) async { | ||||
|     if (state.isLoading) return; | ||||
|     if (state.total > 0 && state.members.length >= state.total) return; | ||||
|  | ||||
|     state = state.copyWith(isLoading: true, error: null); | ||||
|  | ||||
|     try { | ||||
|       final response = await _apiClient.get( | ||||
|         '/publishers/$publisherUname/members', | ||||
|         queryParameters: {'offset': offset, 'take': take}, | ||||
|       ); | ||||
|  | ||||
|       final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||
|       final List<dynamic> data = response.data; | ||||
|       final members = data.map((e) => SnPublisherMember.fromJson(e)).toList(); | ||||
|  | ||||
|       state = state.copyWith( | ||||
|         members: [...state.members, ...members], | ||||
|         total: total, | ||||
|         isLoading: false, | ||||
|       ); | ||||
|     } catch (e) { | ||||
|       state = state.copyWith(error: e.toString(), isLoading: false); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void reset() { | ||||
|     state = const PublisherMemberState(members: [], isLoading: false, total: 0); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _PublisherMemberListSheet extends HookConsumerWidget { | ||||
|   final String publisherUname; | ||||
|   const _PublisherMemberListSheet({required this.publisherUname}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final publisherIdentity = ref.watch( | ||||
|       publisherIdentityProvider(publisherUname), | ||||
|     ); | ||||
|     final memberListProvider = publisherMemberListNotifierProvider( | ||||
|       publisherUname, | ||||
|     ); | ||||
|     final memberState = ref.watch(publisherMemberStateProvider(publisherUname)); | ||||
|     final memberNotifier = ref.read( | ||||
|       publisherMemberStateProvider(publisherUname).notifier, | ||||
|     ); | ||||
|  | ||||
|     useEffect(() { | ||||
|       Future(() { | ||||
|         memberNotifier.loadMore(); | ||||
|       }); | ||||
|       return null; | ||||
|     }, []); | ||||
|  | ||||
|     Future<void> invitePerson() async { | ||||
|       final result = await showModalBottomSheet( | ||||
|         isScrollControlled: true, | ||||
|         context: context, | ||||
|         builder: (context) => const AccountPickerSheet(), | ||||
|       ); | ||||
|       if (result == null) return; | ||||
|       try { | ||||
|         final apiClient = ref.watch(apiClientProvider); | ||||
|         await apiClient.post( | ||||
|           '/publishers/$publisherUname/invites', | ||||
|           data: {'related_user_id': result.id, 'role': 0}, | ||||
|         ); | ||||
|         ref.invalidate(memberListProvider); | ||||
|       } catch (err) { | ||||
|         showErrorAlert(err); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return Container( | ||||
|       constraints: BoxConstraints( | ||||
|         maxHeight: MediaQuery.of(context).size.height * 0.8, | ||||
|       ), | ||||
|       child: Column( | ||||
|         children: [ | ||||
|           Padding( | ||||
|             padding: EdgeInsets.only(top: 16, left: 20, right: 16, bottom: 12), | ||||
|             child: Row( | ||||
|               children: [ | ||||
|                 Text( | ||||
|                   'members'.plural(memberState.total), | ||||
|                   style: Theme.of(context).textTheme.headlineSmall?.copyWith( | ||||
|                     fontWeight: FontWeight.w600, | ||||
|                     letterSpacing: -0.5, | ||||
|                   ), | ||||
|                 ), | ||||
|                 const Spacer(), | ||||
|                 IconButton( | ||||
|                   icon: const Icon(Symbols.person_add), | ||||
|                   onPressed: invitePerson, | ||||
|                   style: IconButton.styleFrom(minimumSize: const Size(36, 36)), | ||||
|                 ), | ||||
|                 IconButton( | ||||
|                   icon: const Icon(Symbols.refresh), | ||||
|                   onPressed: () { | ||||
|                     memberNotifier.reset(); | ||||
|                     memberNotifier.loadMore(); | ||||
|                     ref.invalidate(memberListProvider); | ||||
|                   }, | ||||
|                 ), | ||||
|                 IconButton( | ||||
|                   icon: const Icon(Symbols.close), | ||||
|                   onPressed: () => Navigator.pop(context), | ||||
|                   style: IconButton.styleFrom(minimumSize: const Size(36, 36)), | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|           const Divider(height: 1), | ||||
|           Expanded( | ||||
|             child: PagingHelperView( | ||||
|               provider: memberListProvider, | ||||
|               futureRefreshable: memberListProvider.future, | ||||
|               notifierRefreshable: memberListProvider.notifier, | ||||
|               contentBuilder: (data, widgetCount, endItemView) { | ||||
|                 return ListView.builder( | ||||
|                   itemCount: widgetCount, | ||||
|                   itemBuilder: (context, index) { | ||||
|                     if (index == data.items.length) { | ||||
|                       return endItemView; | ||||
|                     } | ||||
|  | ||||
|                     final member = data.items[index]; | ||||
|                     return ListTile( | ||||
|                       contentPadding: EdgeInsets.only(left: 16, right: 12), | ||||
|                       leading: ProfilePictureWidget( | ||||
|                         fileId: member.account!.profile.picture?.id, | ||||
|                       ), | ||||
|                       title: Row( | ||||
|                         spacing: 6, | ||||
|                         children: [ | ||||
|                           Flexible(child: Text(member.account!.nick)), | ||||
|                           if (member.joinedAt == null) | ||||
|                             const Icon(Symbols.pending_actions, size: 20), | ||||
|                         ], | ||||
|                       ), | ||||
|                       subtitle: Row( | ||||
|                         children: [ | ||||
|                           Text( | ||||
|                             member.role >= 100 | ||||
|                                 ? 'permissionOwner' | ||||
|                                 : member.role >= 50 | ||||
|                                 ? 'permissionModerator' | ||||
|                                 : 'permissionMember', | ||||
|                           ).tr(), | ||||
|                           Text('·').bold().padding(horizontal: 6), | ||||
|                           Expanded(child: Text("@${member.account!.name}")), | ||||
|                         ], | ||||
|                       ), | ||||
|                       trailing: Row( | ||||
|                         mainAxisSize: MainAxisSize.min, | ||||
|                         children: [ | ||||
|                           if ((publisherIdentity.value?.role ?? 0) >= 50) | ||||
|                             IconButton( | ||||
|                               icon: const Icon(Symbols.edit), | ||||
|                               onPressed: () { | ||||
|                                 showModalBottomSheet( | ||||
|                                   isScrollControlled: true, | ||||
|                                   context: context, | ||||
|                                   builder: | ||||
|                                       (context) => _PublisherMemberRoleSheet( | ||||
|                                         publisherUname: publisherUname, | ||||
|                                         member: member, | ||||
|                                       ), | ||||
|                                 ).then((value) { | ||||
|                                   if (value != null) { | ||||
|                                     ref.invalidate(memberListProvider); | ||||
|                                   } | ||||
|                                 }); | ||||
|                               }, | ||||
|                             ), | ||||
|                           if ((publisherIdentity.value?.role ?? 0) >= 50) | ||||
|                             IconButton( | ||||
|                               icon: const Icon(Symbols.delete), | ||||
|                               onPressed: () { | ||||
|                                 showConfirmAlert( | ||||
|                                   'removePublisherMemberHint'.tr(), | ||||
|                                   'removePublisherMember'.tr(), | ||||
|                                 ).then((confirm) async { | ||||
|                                   if (confirm != true) return; | ||||
|                                   try { | ||||
|                                     final apiClient = ref.watch( | ||||
|                                       apiClientProvider, | ||||
|                                     ); | ||||
|                                     await apiClient.delete( | ||||
|                                       '/publishers/$publisherUname/members/${member.accountId}', | ||||
|                                     ); | ||||
|                                     ref.invalidate(memberListProvider); | ||||
|                                   } catch (err) { | ||||
|                                     showErrorAlert(err); | ||||
|                                   } | ||||
|                                 }); | ||||
|                               }, | ||||
|                             ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ); | ||||
|                   }, | ||||
|                 ); | ||||
|               }, | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _PublisherMemberRoleSheet extends HookConsumerWidget { | ||||
|   final String publisherUname; | ||||
|   final SnPublisherMember member; | ||||
|  | ||||
|   const _PublisherMemberRoleSheet({ | ||||
|     required this.publisherUname, | ||||
|     required this.member, | ||||
|   }); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final roleController = useTextEditingController( | ||||
|       text: member.role.toString(), | ||||
|     ); | ||||
|  | ||||
|     return Container( | ||||
|       padding: EdgeInsets.only( | ||||
|         bottom: MediaQuery.of(context).viewInsets.bottom, | ||||
|       ), | ||||
|       child: SafeArea( | ||||
|         child: Column( | ||||
|           mainAxisSize: MainAxisSize.min, | ||||
|           crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|           children: [ | ||||
|             Padding( | ||||
|               padding: EdgeInsets.only( | ||||
|                 top: 16, | ||||
|                 left: 20, | ||||
|                 right: 16, | ||||
|                 bottom: 12, | ||||
|               ), | ||||
|               child: Row( | ||||
|                 children: [ | ||||
|                   Text( | ||||
|                     'memberRoleEdit'.tr(args: [member.account!.name]), | ||||
|                     style: Theme.of(context).textTheme.headlineSmall?.copyWith( | ||||
|                       fontWeight: FontWeight.w600, | ||||
|                       letterSpacing: -0.5, | ||||
|                     ), | ||||
|                   ), | ||||
|                   const Spacer(), | ||||
|                   IconButton( | ||||
|                     icon: const Icon(Symbols.close), | ||||
|                     onPressed: () => Navigator.pop(context), | ||||
|                     style: IconButton.styleFrom( | ||||
|                       minimumSize: const Size(36, 36), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ), | ||||
|             const Divider(height: 1), | ||||
|             Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|               children: [ | ||||
|                 Autocomplete<int>( | ||||
|                   optionsBuilder: (TextEditingValue textEditingValue) { | ||||
|                     if (textEditingValue.text.isEmpty) { | ||||
|                       return const [100, 50, 0]; | ||||
|                     } | ||||
|                     final int? value = int.tryParse(textEditingValue.text); | ||||
|                     if (value == null) return const [100, 50, 0]; | ||||
|                     return [100, 50, 0].where( | ||||
|                       (option) => | ||||
|                           option.toString().contains(textEditingValue.text), | ||||
|                     ); | ||||
|                   }, | ||||
|                   onSelected: (int selection) { | ||||
|                     roleController.text = selection.toString(); | ||||
|                   }, | ||||
|                   fieldViewBuilder: ( | ||||
|                     context, | ||||
|                     controller, | ||||
|                     focusNode, | ||||
|                     onFieldSubmitted, | ||||
|                   ) { | ||||
|                     return TextField( | ||||
|                       controller: controller, | ||||
|                       focusNode: focusNode, | ||||
|                       keyboardType: TextInputType.number, | ||||
|                       decoration: InputDecoration( | ||||
|                         labelText: 'memberRole'.tr(), | ||||
|                         helperText: 'memberRoleHint'.tr(), | ||||
|                       ), | ||||
|                       onTapOutside: (event) => focusNode.unfocus(), | ||||
|                     ); | ||||
|                   }, | ||||
|                 ), | ||||
|                 const Gap(16), | ||||
|                 FilledButton.icon( | ||||
|                   onPressed: () async { | ||||
|                     try { | ||||
|                       final newRole = int.parse(roleController.text); | ||||
|                       if (newRole < 0 || newRole > 100) { | ||||
|                         throw 'Role must be between 0 and 100'; | ||||
|                       } | ||||
|  | ||||
|                       final apiClient = ref.read(apiClientProvider); | ||||
|                       await apiClient.patch( | ||||
|                         '/publishers/$publisherUname/members/${member.accountId}/role', | ||||
|                         data: newRole, | ||||
|                       ); | ||||
|  | ||||
|                       if (context.mounted) Navigator.pop(context, true); | ||||
|                     } catch (err) { | ||||
|                       showErrorAlert(err); | ||||
|                     } | ||||
|                   }, | ||||
|                   icon: const Icon(Symbols.save), | ||||
|                   label: const Text('saveChanges').tr(), | ||||
|                 ), | ||||
|               ], | ||||
|             ).padding(vertical: 16, horizontal: 24), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _PublisherInviteSheet extends HookConsumerWidget { | ||||
|   const _PublisherInviteSheet(); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final invites = ref.watch(publisherInvitesProvider); | ||||
|  | ||||
|     Future<void> acceptInvite(SnPublisherMember invite) async { | ||||
|       try { | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post( | ||||
|           '/publishers/invites/${invite.publisher!.name}/accept', | ||||
|         ); | ||||
|         ref.invalidate(publisherInvitesProvider); | ||||
|         ref.invalidate(publishersManagedProvider); | ||||
|       } catch (err) { | ||||
|         showErrorAlert(err); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     Future<void> declineInvite(SnPublisherMember invite) async { | ||||
|       try { | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post( | ||||
|           '/publishers/invites/${invite.publisher!.name}/decline', | ||||
|         ); | ||||
|         ref.invalidate(publisherInvitesProvider); | ||||
|       } catch (err) { | ||||
|         showErrorAlert(err); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return SheetScaffold( | ||||
|       titleText: 'invites'.tr(), | ||||
|       actions: [ | ||||
|         IconButton( | ||||
|           icon: const Icon(Symbols.refresh), | ||||
|           style: IconButton.styleFrom(minimumSize: const Size(36, 36)), | ||||
|           onPressed: () { | ||||
|             ref.invalidate(publisherInvitesProvider); | ||||
|           }, | ||||
|         ), | ||||
|       ], | ||||
|       child: invites.when( | ||||
|         data: | ||||
|             (items) => | ||||
|                 items.isEmpty | ||||
|                     ? Center( | ||||
|                       child: | ||||
|                           Text( | ||||
|                             'invitesEmpty', | ||||
|                             textAlign: TextAlign.center, | ||||
|                           ).tr(), | ||||
|                     ) | ||||
|                     : ListView.builder( | ||||
|                       shrinkWrap: true, | ||||
|                       itemCount: items.length, | ||||
|                       itemBuilder: (context, index) { | ||||
|                         final invite = items[index]; | ||||
|                         return ListTile( | ||||
|                           leading: ProfilePictureWidget( | ||||
|                             fileId: invite.publisher!.picture?.id, | ||||
|                             fallbackIcon: Symbols.group, | ||||
|                           ), | ||||
|                           title: Text(invite.publisher!.nick), | ||||
|                           subtitle: | ||||
|                               Text( | ||||
|                                 invite.role >= 100 | ||||
|                                     ? 'permissionOwner' | ||||
|                                     : invite.role >= 50 | ||||
|                                     ? 'permissionModerator' | ||||
|                                     : 'permissionMember', | ||||
|                               ).tr(), | ||||
|                           trailing: Row( | ||||
|                             mainAxisSize: MainAxisSize.min, | ||||
|                             children: [ | ||||
|                               IconButton( | ||||
|                                 icon: const Icon(Symbols.check), | ||||
|                                 onPressed: () => acceptInvite(invite), | ||||
|                               ), | ||||
|                               IconButton( | ||||
|                                 icon: const Icon(Symbols.close), | ||||
|                                 onPressed: () => declineInvite(invite), | ||||
|                               ), | ||||
|                             ], | ||||
|                           ), | ||||
|                         ); | ||||
|                       }, | ||||
|                     ), | ||||
|         loading: () => const Center(child: CircularProgressIndicator()), | ||||
|         error: | ||||
|             (error, _) => ResponseErrorWidget( | ||||
|               error: error, | ||||
|               onRetry: () => ref.invalidate(publisherInvitesProvider), | ||||
|             ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -149,5 +149,300 @@ class _PublisherStatsProviderElement | ||||
|   String? get uname => (origin as PublisherStatsProvider).uname; | ||||
| } | ||||
|  | ||||
| String _$publisherIdentityHash() => r'f7fd986a303a729ca5557022fceb37cd01fa17f3'; | ||||
|  | ||||
| /// See also [publisherIdentity]. | ||||
| @ProviderFor(publisherIdentity) | ||||
| const publisherIdentityProvider = PublisherIdentityFamily(); | ||||
|  | ||||
| /// See also [publisherIdentity]. | ||||
| class PublisherIdentityFamily extends Family<AsyncValue<SnPublisherMember?>> { | ||||
|   /// See also [publisherIdentity]. | ||||
|   const PublisherIdentityFamily(); | ||||
|  | ||||
|   /// See also [publisherIdentity]. | ||||
|   PublisherIdentityProvider call(String uname) { | ||||
|     return PublisherIdentityProvider(uname); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   PublisherIdentityProvider getProviderOverride( | ||||
|     covariant PublisherIdentityProvider provider, | ||||
|   ) { | ||||
|     return call(provider.uname); | ||||
|   } | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||
|       _allTransitiveDependencies; | ||||
|  | ||||
|   @override | ||||
|   String? get name => r'publisherIdentityProvider'; | ||||
| } | ||||
|  | ||||
| /// See also [publisherIdentity]. | ||||
| class PublisherIdentityProvider | ||||
|     extends AutoDisposeFutureProvider<SnPublisherMember?> { | ||||
|   /// See also [publisherIdentity]. | ||||
|   PublisherIdentityProvider(String uname) | ||||
|     : this._internal( | ||||
|         (ref) => publisherIdentity(ref as PublisherIdentityRef, uname), | ||||
|         from: publisherIdentityProvider, | ||||
|         name: r'publisherIdentityProvider', | ||||
|         debugGetCreateSourceHash: | ||||
|             const bool.fromEnvironment('dart.vm.product') | ||||
|                 ? null | ||||
|                 : _$publisherIdentityHash, | ||||
|         dependencies: PublisherIdentityFamily._dependencies, | ||||
|         allTransitiveDependencies: | ||||
|             PublisherIdentityFamily._allTransitiveDependencies, | ||||
|         uname: uname, | ||||
|       ); | ||||
|  | ||||
|   PublisherIdentityProvider._internal( | ||||
|     super._createNotifier, { | ||||
|     required super.name, | ||||
|     required super.dependencies, | ||||
|     required super.allTransitiveDependencies, | ||||
|     required super.debugGetCreateSourceHash, | ||||
|     required super.from, | ||||
|     required this.uname, | ||||
|   }) : super.internal(); | ||||
|  | ||||
|   final String uname; | ||||
|  | ||||
|   @override | ||||
|   Override overrideWith( | ||||
|     FutureOr<SnPublisherMember?> Function(PublisherIdentityRef provider) create, | ||||
|   ) { | ||||
|     return ProviderOverride( | ||||
|       origin: this, | ||||
|       override: PublisherIdentityProvider._internal( | ||||
|         (ref) => create(ref as PublisherIdentityRef), | ||||
|         from: from, | ||||
|         name: null, | ||||
|         dependencies: null, | ||||
|         allTransitiveDependencies: null, | ||||
|         debugGetCreateSourceHash: null, | ||||
|         uname: uname, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   AutoDisposeFutureProviderElement<SnPublisherMember?> createElement() { | ||||
|     return _PublisherIdentityProviderElement(this); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return other is PublisherIdentityProvider && other.uname == uname; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int get hashCode { | ||||
|     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||
|     hash = _SystemHash.combine(hash, uname.hashCode); | ||||
|  | ||||
|     return _SystemHash.finish(hash); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| mixin PublisherIdentityRef on AutoDisposeFutureProviderRef<SnPublisherMember?> { | ||||
|   /// The parameter `uname` of this provider. | ||||
|   String get uname; | ||||
| } | ||||
|  | ||||
| class _PublisherIdentityProviderElement | ||||
|     extends AutoDisposeFutureProviderElement<SnPublisherMember?> | ||||
|     with PublisherIdentityRef { | ||||
|   _PublisherIdentityProviderElement(super.provider); | ||||
|  | ||||
|   @override | ||||
|   String get uname => (origin as PublisherIdentityProvider).uname; | ||||
| } | ||||
|  | ||||
| String _$publisherInvitesHash() => r'488cd443407895ce11f4edff07cb6ea58f2aa018'; | ||||
|  | ||||
| /// See also [publisherInvites]. | ||||
| @ProviderFor(publisherInvites) | ||||
| final publisherInvitesProvider = | ||||
|     AutoDisposeFutureProvider<List<SnPublisherMember>>.internal( | ||||
|       publisherInvites, | ||||
|       name: r'publisherInvitesProvider', | ||||
|       debugGetCreateSourceHash: | ||||
|           const bool.fromEnvironment('dart.vm.product') | ||||
|               ? null | ||||
|               : _$publisherInvitesHash, | ||||
|       dependencies: null, | ||||
|       allTransitiveDependencies: null, | ||||
|     ); | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| typedef PublisherInvitesRef = | ||||
|     AutoDisposeFutureProviderRef<List<SnPublisherMember>>; | ||||
| String _$publisherMemberListNotifierHash() => | ||||
|     r'237e8f39c9757a6cbdff817853c697539242ad2a'; | ||||
|  | ||||
| abstract class _$PublisherMemberListNotifier | ||||
|     extends | ||||
|         BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPublisherMember>> { | ||||
|   late final String uname; | ||||
|  | ||||
|   FutureOr<CursorPagingData<SnPublisherMember>> build(String uname); | ||||
| } | ||||
|  | ||||
| /// See also [PublisherMemberListNotifier]. | ||||
| @ProviderFor(PublisherMemberListNotifier) | ||||
| const publisherMemberListNotifierProvider = PublisherMemberListNotifierFamily(); | ||||
|  | ||||
| /// See also [PublisherMemberListNotifier]. | ||||
| class PublisherMemberListNotifierFamily | ||||
|     extends Family<AsyncValue<CursorPagingData<SnPublisherMember>>> { | ||||
|   /// See also [PublisherMemberListNotifier]. | ||||
|   const PublisherMemberListNotifierFamily(); | ||||
|  | ||||
|   /// See also [PublisherMemberListNotifier]. | ||||
|   PublisherMemberListNotifierProvider call(String uname) { | ||||
|     return PublisherMemberListNotifierProvider(uname); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   PublisherMemberListNotifierProvider getProviderOverride( | ||||
|     covariant PublisherMemberListNotifierProvider provider, | ||||
|   ) { | ||||
|     return call(provider.uname); | ||||
|   } | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||
|       _allTransitiveDependencies; | ||||
|  | ||||
|   @override | ||||
|   String? get name => r'publisherMemberListNotifierProvider'; | ||||
| } | ||||
|  | ||||
| /// See also [PublisherMemberListNotifier]. | ||||
| class PublisherMemberListNotifierProvider | ||||
|     extends | ||||
|         AutoDisposeAsyncNotifierProviderImpl< | ||||
|           PublisherMemberListNotifier, | ||||
|           CursorPagingData<SnPublisherMember> | ||||
|         > { | ||||
|   /// See also [PublisherMemberListNotifier]. | ||||
|   PublisherMemberListNotifierProvider(String uname) | ||||
|     : this._internal( | ||||
|         () => PublisherMemberListNotifier()..uname = uname, | ||||
|         from: publisherMemberListNotifierProvider, | ||||
|         name: r'publisherMemberListNotifierProvider', | ||||
|         debugGetCreateSourceHash: | ||||
|             const bool.fromEnvironment('dart.vm.product') | ||||
|                 ? null | ||||
|                 : _$publisherMemberListNotifierHash, | ||||
|         dependencies: PublisherMemberListNotifierFamily._dependencies, | ||||
|         allTransitiveDependencies: | ||||
|             PublisherMemberListNotifierFamily._allTransitiveDependencies, | ||||
|         uname: uname, | ||||
|       ); | ||||
|  | ||||
|   PublisherMemberListNotifierProvider._internal( | ||||
|     super._createNotifier, { | ||||
|     required super.name, | ||||
|     required super.dependencies, | ||||
|     required super.allTransitiveDependencies, | ||||
|     required super.debugGetCreateSourceHash, | ||||
|     required super.from, | ||||
|     required this.uname, | ||||
|   }) : super.internal(); | ||||
|  | ||||
|   final String uname; | ||||
|  | ||||
|   @override | ||||
|   FutureOr<CursorPagingData<SnPublisherMember>> runNotifierBuild( | ||||
|     covariant PublisherMemberListNotifier notifier, | ||||
|   ) { | ||||
|     return notifier.build(uname); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Override overrideWith(PublisherMemberListNotifier Function() create) { | ||||
|     return ProviderOverride( | ||||
|       origin: this, | ||||
|       override: PublisherMemberListNotifierProvider._internal( | ||||
|         () => create()..uname = uname, | ||||
|         from: from, | ||||
|         name: null, | ||||
|         dependencies: null, | ||||
|         allTransitiveDependencies: null, | ||||
|         debugGetCreateSourceHash: null, | ||||
|         uname: uname, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   AutoDisposeAsyncNotifierProviderElement< | ||||
|     PublisherMemberListNotifier, | ||||
|     CursorPagingData<SnPublisherMember> | ||||
|   > | ||||
|   createElement() { | ||||
|     return _PublisherMemberListNotifierProviderElement(this); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return other is PublisherMemberListNotifierProvider && other.uname == uname; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int get hashCode { | ||||
|     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||
|     hash = _SystemHash.combine(hash, uname.hashCode); | ||||
|  | ||||
|     return _SystemHash.finish(hash); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| mixin PublisherMemberListNotifierRef | ||||
|     on | ||||
|         AutoDisposeAsyncNotifierProviderRef< | ||||
|           CursorPagingData<SnPublisherMember> | ||||
|         > { | ||||
|   /// The parameter `uname` of this provider. | ||||
|   String get uname; | ||||
| } | ||||
|  | ||||
| class _PublisherMemberListNotifierProviderElement | ||||
|     extends | ||||
|         AutoDisposeAsyncNotifierProviderElement< | ||||
|           PublisherMemberListNotifier, | ||||
|           CursorPagingData<SnPublisherMember> | ||||
|         > | ||||
|     with PublisherMemberListNotifierRef { | ||||
|   _PublisherMemberListNotifierProviderElement(super.provider); | ||||
|  | ||||
|   @override | ||||
|   String get uname => (origin as PublisherMemberListNotifierProvider).uname; | ||||
| } | ||||
|  | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import 'package:go_router/go_router.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:image_picker/image_picker.dart'; | ||||
| import 'package:island/models/file.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/models/realm.dart'; | ||||
| import 'package:island/pods/config.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
|   | ||||
							
								
								
									
										65
									
								
								lib/screens/developers/apps.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								lib/screens/developers/apps.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/custom_app.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/widgets/app_scaffold.dart'; | ||||
| import 'package:island/widgets/response.dart'; | ||||
| import 'package:material_symbols_icons/symbols.dart'; | ||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||
|  | ||||
| part 'apps.g.dart'; | ||||
|  | ||||
| @riverpod | ||||
| Future<List<CustomApp>> customApps(Ref ref, String publisherName) async { | ||||
|   final client = ref.watch(apiClientProvider); | ||||
|   final resp = await client.get('/developers/$publisherName/apps'); | ||||
|   return resp.data.map((e) => CustomApp.fromJson(e)).cast<CustomApp>().toList(); | ||||
| } | ||||
|  | ||||
| class CustomAppsScreen extends HookConsumerWidget { | ||||
|   final String publisherName; | ||||
|   const CustomAppsScreen({super.key, required this.publisherName}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final apps = ref.watch(customAppsProvider(publisherName)); | ||||
|  | ||||
|     return AppScaffold( | ||||
|       appBar: AppBar(title: Text('customApps').tr()), | ||||
|       floatingActionButton: FloatingActionButton( | ||||
|         child: const Icon(Symbols.add), | ||||
|         onPressed: () { | ||||
|           context.push('/developers/$publisherName/apps/new'); | ||||
|         }, | ||||
|       ), | ||||
|       body: apps.when( | ||||
|         data: (data) { | ||||
|           if (data.isEmpty) { | ||||
|             return Center(child: Text('noCustomApps').tr()); | ||||
|           } | ||||
|           return ListView.builder( | ||||
|             itemCount: data.length, | ||||
|             itemBuilder: (context, index) { | ||||
|               final app = data[index]; | ||||
|               return ListTile( | ||||
|                 title: Text(app.name), | ||||
|                 subtitle: Text(app.slug), | ||||
|                 onTap: () { | ||||
|                   context.push('/developers/$publisherName/apps/${app.id}'); | ||||
|                 }, | ||||
|               ); | ||||
|             }, | ||||
|           ); | ||||
|         }, | ||||
|         loading: () => const Center(child: CircularProgressIndicator()), | ||||
|         error: | ||||
|             (err, stack) => ResponseErrorWidget( | ||||
|               error: err, | ||||
|               onRetry: () => ref.invalidate(customAppsProvider(publisherName)), | ||||
|             ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										151
									
								
								lib/screens/developers/apps.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								lib/screens/developers/apps.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'apps.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$customAppsHash() => r'1dec11573b9d987c3adbdf4732b3781a6f40172a'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
|   _SystemHash._(); | ||||
|  | ||||
|   static int combine(int hash, int value) { | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + value); | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | ||||
|     return hash ^ (hash >> 6); | ||||
|   } | ||||
|  | ||||
|   static int finish(int hash) { | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | ||||
|     // ignore: parameter_assignments | ||||
|     hash = hash ^ (hash >> 11); | ||||
|     return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// See also [customApps]. | ||||
| @ProviderFor(customApps) | ||||
| const customAppsProvider = CustomAppsFamily(); | ||||
|  | ||||
| /// See also [customApps]. | ||||
| class CustomAppsFamily extends Family<AsyncValue<List<CustomApp>>> { | ||||
|   /// See also [customApps]. | ||||
|   const CustomAppsFamily(); | ||||
|  | ||||
|   /// See also [customApps]. | ||||
|   CustomAppsProvider call(String publisherName) { | ||||
|     return CustomAppsProvider(publisherName); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   CustomAppsProvider getProviderOverride( | ||||
|     covariant CustomAppsProvider provider, | ||||
|   ) { | ||||
|     return call(provider.publisherName); | ||||
|   } | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||
|       _allTransitiveDependencies; | ||||
|  | ||||
|   @override | ||||
|   String? get name => r'customAppsProvider'; | ||||
| } | ||||
|  | ||||
| /// See also [customApps]. | ||||
| class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | ||||
|   /// See also [customApps]. | ||||
|   CustomAppsProvider(String publisherName) | ||||
|     : this._internal( | ||||
|         (ref) => customApps(ref as CustomAppsRef, publisherName), | ||||
|         from: customAppsProvider, | ||||
|         name: r'customAppsProvider', | ||||
|         debugGetCreateSourceHash: | ||||
|             const bool.fromEnvironment('dart.vm.product') | ||||
|                 ? null | ||||
|                 : _$customAppsHash, | ||||
|         dependencies: CustomAppsFamily._dependencies, | ||||
|         allTransitiveDependencies: CustomAppsFamily._allTransitiveDependencies, | ||||
|         publisherName: publisherName, | ||||
|       ); | ||||
|  | ||||
|   CustomAppsProvider._internal( | ||||
|     super._createNotifier, { | ||||
|     required super.name, | ||||
|     required super.dependencies, | ||||
|     required super.allTransitiveDependencies, | ||||
|     required super.debugGetCreateSourceHash, | ||||
|     required super.from, | ||||
|     required this.publisherName, | ||||
|   }) : super.internal(); | ||||
|  | ||||
|   final String publisherName; | ||||
|  | ||||
|   @override | ||||
|   Override overrideWith( | ||||
|     FutureOr<List<CustomApp>> Function(CustomAppsRef provider) create, | ||||
|   ) { | ||||
|     return ProviderOverride( | ||||
|       origin: this, | ||||
|       override: CustomAppsProvider._internal( | ||||
|         (ref) => create(ref as CustomAppsRef), | ||||
|         from: from, | ||||
|         name: null, | ||||
|         dependencies: null, | ||||
|         allTransitiveDependencies: null, | ||||
|         debugGetCreateSourceHash: null, | ||||
|         publisherName: publisherName, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   AutoDisposeFutureProviderElement<List<CustomApp>> createElement() { | ||||
|     return _CustomAppsProviderElement(this); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return other is CustomAppsProvider && other.publisherName == publisherName; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int get hashCode { | ||||
|     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||
|     hash = _SystemHash.combine(hash, publisherName.hashCode); | ||||
|  | ||||
|     return _SystemHash.finish(hash); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| mixin CustomAppsRef on AutoDisposeFutureProviderRef<List<CustomApp>> { | ||||
|   /// The parameter `publisherName` of this provider. | ||||
|   String get publisherName; | ||||
| } | ||||
|  | ||||
| class _CustomAppsProviderElement | ||||
|     extends AutoDisposeFutureProviderElement<List<CustomApp>> | ||||
|     with CustomAppsRef { | ||||
|   _CustomAppsProviderElement(super.provider); | ||||
|  | ||||
|   @override | ||||
|   String get publisherName => (origin as CustomAppsProvider).publisherName; | ||||
| } | ||||
|  | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||
							
								
								
									
										253
									
								
								lib/screens/developers/edit_app.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								lib/screens/developers/edit_app.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,253 @@ | ||||
| import 'package:croppy/croppy.dart' hide cropImage; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:image_picker/image_picker.dart'; | ||||
| import 'package:island/models/custom_app.dart'; | ||||
| import 'package:island/models/file.dart'; | ||||
| import 'package:island/pods/config.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/screens/developers/apps.dart'; | ||||
| import 'package:island/services/file.dart'; | ||||
| import 'package:island/widgets/alert.dart'; | ||||
| import 'package:island/widgets/app_scaffold.dart'; | ||||
| import 'package:island/widgets/content/cloud_files.dart'; | ||||
| import 'package:island/widgets/response.dart'; | ||||
| import 'package:material_symbols_icons/symbols.dart'; | ||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||
| import 'package:styled_widget/styled_widget.dart'; | ||||
|  | ||||
| part 'edit_app.g.dart'; | ||||
|  | ||||
| @riverpod | ||||
| Future<CustomApp?> customApp(Ref ref, String publisherName, String id) async { | ||||
|   final client = ref.watch(apiClientProvider); | ||||
|   final resp = await client.get('/developers/$publisherName/apps/$id'); | ||||
|   return CustomApp.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| class EditAppScreen extends HookConsumerWidget { | ||||
|   final String publisherName; | ||||
|   final String? id; | ||||
|   const EditAppScreen({super.key, required this.publisherName, this.id}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final isNew = id == null; | ||||
|     final app = isNew ? null : ref.watch(customAppProvider(publisherName, id!)); | ||||
|  | ||||
|     final formKey = useMemoized(() => GlobalKey<FormState>()); | ||||
|  | ||||
|     final nameController = useTextEditingController(); | ||||
|     final slugController = useTextEditingController(); | ||||
|     final descriptionController = useTextEditingController(); | ||||
|     final picture = useState<SnCloudFile?>(null); | ||||
|     final background = useState<SnCloudFile?>(null); | ||||
|  | ||||
|     final submitting = useState(false); | ||||
|  | ||||
|     useEffect(() { | ||||
|       if (app?.value != null) { | ||||
|         nameController.text = app!.value!.name; | ||||
|         slugController.text = app.value!.slug; | ||||
|         descriptionController.text = app.value!.description ?? ''; | ||||
|         picture.value = app.value!.picture; | ||||
|         background.value = app.value!.background; | ||||
|       } | ||||
|       return null; | ||||
|     }, [app]); | ||||
|  | ||||
|     void setPicture(String position) async { | ||||
|       showLoadingModal(context); | ||||
|       var result = await ref | ||||
|           .read(imagePickerProvider) | ||||
|           .pickImage(source: ImageSource.gallery); | ||||
|       if (result == null) { | ||||
|         if (context.mounted) hideLoadingModal(context); | ||||
|         return; | ||||
|       } | ||||
|       if (!context.mounted) return; | ||||
|       hideLoadingModal(context); | ||||
|       result = await cropImage( | ||||
|         context, | ||||
|         image: result, | ||||
|         allowedAspectRatios: [ | ||||
|           if (position == 'background') | ||||
|             const CropAspectRatio(height: 7, width: 16) | ||||
|           else | ||||
|             const CropAspectRatio(height: 1, width: 1), | ||||
|         ], | ||||
|       ); | ||||
|       if (result == null) { | ||||
|         if (context.mounted) hideLoadingModal(context); | ||||
|         return; | ||||
|       } | ||||
|       if (!context.mounted) return; | ||||
|       showLoadingModal(context); | ||||
|  | ||||
|       submitting.value = true; | ||||
|       try { | ||||
|         final baseUrl = ref.watch(serverUrlProvider); | ||||
|         final token = await getToken(ref.watch(tokenProvider)); | ||||
|         if (token == null) throw ArgumentError('Token is null'); | ||||
|         final cloudFile = | ||||
|             await putMediaToCloud( | ||||
|               fileData: UniversalFile( | ||||
|                 data: result, | ||||
|                 type: UniversalFileType.image, | ||||
|               ), | ||||
|               atk: token, | ||||
|               baseUrl: baseUrl, | ||||
|               filename: result.name, | ||||
|               mimetype: result.mimeType ?? 'image/jpeg', | ||||
|             ).future; | ||||
|         if (cloudFile == null) { | ||||
|           throw ArgumentError('Failed to upload the file...'); | ||||
|         } | ||||
|         switch (position) { | ||||
|           case 'picture': | ||||
|             picture.value = cloudFile; | ||||
|           case 'background': | ||||
|             background.value = cloudFile; | ||||
|         } | ||||
|       } catch (err) { | ||||
|         showErrorAlert(err); | ||||
|       } finally { | ||||
|         if (context.mounted) hideLoadingModal(context); | ||||
|         submitting.value = false; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     void performAction() async { | ||||
|       final client = ref.read(apiClientProvider); | ||||
|       final data = { | ||||
|         'name': nameController.text, | ||||
|         'slug': slugController.text, | ||||
|         'description': descriptionController.text, | ||||
|         'picture_id': picture.value?.id, | ||||
|         'background_id': background.value?.id, | ||||
|       }; | ||||
|       if (isNew) { | ||||
|         await client.post('/developers/$publisherName/apps', data: data); | ||||
|       } else { | ||||
|         await client.patch('/developers/$publisherName/apps/$id', data: data); | ||||
|       } | ||||
|       ref.invalidate(customAppsProvider(publisherName)); | ||||
|       if (context.mounted) { | ||||
|         Navigator.pop(context); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return AppScaffold( | ||||
|       appBar: AppBar( | ||||
|         title: Text(isNew ? 'createCustomApp'.tr() : 'editCustomApp'.tr()), | ||||
|       ), | ||||
|       body: | ||||
|           app == null && !isNew | ||||
|               ? const Center(child: CircularProgressIndicator()) | ||||
|               : app?.hasError == true && !isNew | ||||
|               ? ResponseErrorWidget( | ||||
|                 error: app!.error, | ||||
|                 onRetry: | ||||
|                     () => ref.invalidate(customAppProvider(publisherName, id!)), | ||||
|               ) | ||||
|               : 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('background'); | ||||
|                             }, | ||||
|                           ), | ||||
|                           Positioned( | ||||
|                             left: 20, | ||||
|                             bottom: -32, | ||||
|                             child: GestureDetector( | ||||
|                               child: ProfilePictureWidget( | ||||
|                                 fileId: picture.value?.id, | ||||
|                                 radius: 40, | ||||
|                                 fallbackIcon: Symbols.apps, | ||||
|                               ), | ||||
|                               onTap: () { | ||||
|                                 setPicture('picture'); | ||||
|                               }, | ||||
|                             ), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ).padding(bottom: 32), | ||||
|                     Form( | ||||
|                       key: formKey, | ||||
|                       child: Column( | ||||
|                         children: [ | ||||
|                           TextFormField( | ||||
|                             controller: nameController, | ||||
|                             decoration: InputDecoration(labelText: 'name'.tr()), | ||||
|                             onTapOutside: | ||||
|                                 (_) => | ||||
|                                     FocusManager.instance.primaryFocus | ||||
|                                         ?.unfocus(), | ||||
|                           ), | ||||
|                           const SizedBox(height: 16), | ||||
|                           TextFormField( | ||||
|                             controller: slugController, | ||||
|                             decoration: InputDecoration( | ||||
|                               labelText: 'slug'.tr(), | ||||
|                               helperText: 'slugHint'.tr(), | ||||
|                             ), | ||||
|                             onTapOutside: | ||||
|                                 (_) => | ||||
|                                     FocusManager.instance.primaryFocus | ||||
|                                         ?.unfocus(), | ||||
|                           ), | ||||
|                           const SizedBox(height: 16), | ||||
|                           TextFormField( | ||||
|                             controller: descriptionController, | ||||
|                             decoration: InputDecoration( | ||||
|                               labelText: 'description'.tr(), | ||||
|                             ), | ||||
|                             maxLines: 3, | ||||
|                             onTapOutside: | ||||
|                                 (_) => | ||||
|                                     FocusManager.instance.primaryFocus | ||||
|                                         ?.unfocus(), | ||||
|                           ), | ||||
|                           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), | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|               ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										161
									
								
								lib/screens/developers/edit_app.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								lib/screens/developers/edit_app.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'edit_app.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$customAppHash() => r'aa4d1fb803c47a99cbacf6d91481f4fce3fda457'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
|   _SystemHash._(); | ||||
|  | ||||
|   static int combine(int hash, int value) { | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + value); | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | ||||
|     return hash ^ (hash >> 6); | ||||
|   } | ||||
|  | ||||
|   static int finish(int hash) { | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | ||||
|     // ignore: parameter_assignments | ||||
|     hash = hash ^ (hash >> 11); | ||||
|     return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// See also [customApp]. | ||||
| @ProviderFor(customApp) | ||||
| const customAppProvider = CustomAppFamily(); | ||||
|  | ||||
| /// See also [customApp]. | ||||
| class CustomAppFamily extends Family<AsyncValue<CustomApp?>> { | ||||
|   /// See also [customApp]. | ||||
|   const CustomAppFamily(); | ||||
|  | ||||
|   /// See also [customApp]. | ||||
|   CustomAppProvider call(String publisherName, String id) { | ||||
|     return CustomAppProvider(publisherName, id); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   CustomAppProvider getProviderOverride(covariant CustomAppProvider provider) { | ||||
|     return call(provider.publisherName, provider.id); | ||||
|   } | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||
|       _allTransitiveDependencies; | ||||
|  | ||||
|   @override | ||||
|   String? get name => r'customAppProvider'; | ||||
| } | ||||
|  | ||||
| /// See also [customApp]. | ||||
| class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | ||||
|   /// See also [customApp]. | ||||
|   CustomAppProvider(String publisherName, String id) | ||||
|     : this._internal( | ||||
|         (ref) => customApp(ref as CustomAppRef, publisherName, id), | ||||
|         from: customAppProvider, | ||||
|         name: r'customAppProvider', | ||||
|         debugGetCreateSourceHash: | ||||
|             const bool.fromEnvironment('dart.vm.product') | ||||
|                 ? null | ||||
|                 : _$customAppHash, | ||||
|         dependencies: CustomAppFamily._dependencies, | ||||
|         allTransitiveDependencies: CustomAppFamily._allTransitiveDependencies, | ||||
|         publisherName: publisherName, | ||||
|         id: id, | ||||
|       ); | ||||
|  | ||||
|   CustomAppProvider._internal( | ||||
|     super._createNotifier, { | ||||
|     required super.name, | ||||
|     required super.dependencies, | ||||
|     required super.allTransitiveDependencies, | ||||
|     required super.debugGetCreateSourceHash, | ||||
|     required super.from, | ||||
|     required this.publisherName, | ||||
|     required this.id, | ||||
|   }) : super.internal(); | ||||
|  | ||||
|   final String publisherName; | ||||
|   final String id; | ||||
|  | ||||
|   @override | ||||
|   Override overrideWith( | ||||
|     FutureOr<CustomApp?> Function(CustomAppRef provider) create, | ||||
|   ) { | ||||
|     return ProviderOverride( | ||||
|       origin: this, | ||||
|       override: CustomAppProvider._internal( | ||||
|         (ref) => create(ref as CustomAppRef), | ||||
|         from: from, | ||||
|         name: null, | ||||
|         dependencies: null, | ||||
|         allTransitiveDependencies: null, | ||||
|         debugGetCreateSourceHash: null, | ||||
|         publisherName: publisherName, | ||||
|         id: id, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   AutoDisposeFutureProviderElement<CustomApp?> createElement() { | ||||
|     return _CustomAppProviderElement(this); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return other is CustomAppProvider && | ||||
|         other.publisherName == publisherName && | ||||
|         other.id == id; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int get hashCode { | ||||
|     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||
|     hash = _SystemHash.combine(hash, publisherName.hashCode); | ||||
|     hash = _SystemHash.combine(hash, id.hashCode); | ||||
|  | ||||
|     return _SystemHash.finish(hash); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| mixin CustomAppRef on AutoDisposeFutureProviderRef<CustomApp?> { | ||||
|   /// The parameter `publisherName` of this provider. | ||||
|   String get publisherName; | ||||
|  | ||||
|   /// The parameter `id` of this provider. | ||||
|   String get id; | ||||
| } | ||||
|  | ||||
| class _CustomAppProviderElement | ||||
|     extends AutoDisposeFutureProviderElement<CustomApp?> | ||||
|     with CustomAppRef { | ||||
|   _CustomAppProviderElement(super.provider); | ||||
|  | ||||
|   @override | ||||
|   String get publisherName => (origin as CustomAppProvider).publisherName; | ||||
|   @override | ||||
|   String get id => (origin as CustomAppProvider).id; | ||||
| } | ||||
|  | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||
							
								
								
									
										380
									
								
								lib/screens/developers/hub.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								lib/screens/developers/hub.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | ||||
| import 'package:dropdown_button2/dropdown_button2.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/developer.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/screens/creators/publishers.dart'; | ||||
| import 'package:island/services/responsive.dart'; | ||||
| import 'package:island/widgets/alert.dart'; | ||||
| import 'package:island/widgets/app_scaffold.dart'; | ||||
| import 'package:island/widgets/content/cloud_files.dart'; | ||||
| import 'package:island/widgets/content/sheet.dart'; | ||||
| import 'package:island/widgets/response.dart'; | ||||
| import 'package:material_symbols_icons/symbols.dart'; | ||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||
| import 'package:styled_widget/styled_widget.dart'; | ||||
|  | ||||
| part 'hub.g.dart'; | ||||
|  | ||||
| @riverpod | ||||
| 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'); | ||||
|   return DeveloperStats.fromJson(resp.data); | ||||
| } | ||||
|  | ||||
| @riverpod | ||||
| Future<List<SnPublisher>> developers(Ref ref) async { | ||||
|   final client = ref.watch(apiClientProvider); | ||||
|   final resp = await client.get('/developers'); | ||||
|   return resp.data | ||||
|       .map((e) => SnPublisher.fromJson(e)) | ||||
|       .cast<SnPublisher>() | ||||
|       .toList(); | ||||
| } | ||||
|  | ||||
| class DeveloperHubShellScreen extends StatelessWidget { | ||||
|   final Widget child; | ||||
|   const DeveloperHubShellScreen({super.key, required this.child}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final isWide = isWideScreen(context); | ||||
|     if (isWide) { | ||||
|       return Row( | ||||
|         children: [ | ||||
|           SizedBox(width: 360, child: const DeveloperHubScreen(isAside: true)), | ||||
|           const VerticalDivider(width: 1), | ||||
|           Expanded(child: child), | ||||
|         ], | ||||
|       ); | ||||
|     } | ||||
|     return child; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class DeveloperHubScreen extends HookConsumerWidget { | ||||
|   final bool isAside; | ||||
|   const DeveloperHubScreen({super.key, this.isAside = false}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final isWide = isWideScreen(context); | ||||
|     if (isWide && !isAside) { | ||||
|       return Container(color: Theme.of(context).colorScheme.surface); | ||||
|     } | ||||
|  | ||||
|     final developers = ref.watch(developersProvider); | ||||
|     final currentDeveloper = useState<SnPublisher?>( | ||||
|       developers.value?.firstOrNull, | ||||
|     ); | ||||
|  | ||||
|     final List<DropdownMenuItem<SnPublisher>> developersMenu = developers.when( | ||||
|       data: | ||||
|           (data) => | ||||
|               data | ||||
|                   .map( | ||||
|                     (item) => DropdownMenuItem<SnPublisher>( | ||||
|                       value: item, | ||||
|                       child: ListTile( | ||||
|                         minTileHeight: 48, | ||||
|                         leading: ProfilePictureWidget( | ||||
|                           radius: 16, | ||||
|                           fileId: item.picture?.id, | ||||
|                         ), | ||||
|                         title: Text(item.nick), | ||||
|                         subtitle: Text('@${item.name}'), | ||||
|                         trailing: | ||||
|                             currentDeveloper.value?.id == item.id | ||||
|                                 ? const Icon(Icons.check) | ||||
|                                 : null, | ||||
|                         contentPadding: EdgeInsets.symmetric(horizontal: 8), | ||||
|                       ), | ||||
|                     ), | ||||
|                   ) | ||||
|                   .toList(), | ||||
|       loading: () => [], | ||||
|       error: (_, _) => [], | ||||
|     ); | ||||
|  | ||||
|     final developerStats = ref.watch( | ||||
|       developerStatsProvider(currentDeveloper.value?.name), | ||||
|     ); | ||||
|  | ||||
|     return AppScaffold( | ||||
|       noBackground: false, | ||||
|       appBar: AppBar( | ||||
|         leading: !isWide ? const PageBackButton() : null, | ||||
|         title: Text('developerHub').tr(), | ||||
|         actions: [ | ||||
|           DropdownButtonHideUnderline( | ||||
|             child: DropdownButton2<SnPublisher>( | ||||
|               alignment: Alignment.centerRight, | ||||
|               value: currentDeveloper.value, | ||||
|               hint: CircleAvatar( | ||||
|                 radius: 16, | ||||
|                 child: Icon( | ||||
|                   Symbols.person, | ||||
|                   color: Theme.of( | ||||
|                     context, | ||||
|                   ).colorScheme.onSecondaryContainer.withOpacity(0.9), | ||||
|                   fill: 1, | ||||
|                 ), | ||||
|               ).center().padding(right: 8), | ||||
|               items: [...developersMenu], | ||||
|               onChanged: (value) { | ||||
|                 currentDeveloper.value = value; | ||||
|               }, | ||||
|               selectedItemBuilder: (context) { | ||||
|                 return [ | ||||
|                   ...developersMenu.map( | ||||
|                     (e) => ProfilePictureWidget( | ||||
|                       radius: 16, | ||||
|                       fileId: e.value?.picture?.id, | ||||
|                     ).center().padding(right: 8), | ||||
|                   ), | ||||
|                 ]; | ||||
|               }, | ||||
|               buttonStyleData: ButtonStyleData( | ||||
|                 height: 40, | ||||
|                 padding: const EdgeInsets.only(left: 14, right: 8), | ||||
|                 decoration: BoxDecoration( | ||||
|                   borderRadius: BorderRadius.circular(20), | ||||
|                 ), | ||||
|               ), | ||||
|               dropdownStyleData: DropdownStyleData( | ||||
|                 width: 320, | ||||
|                 padding: const EdgeInsets.symmetric(vertical: 6), | ||||
|                 decoration: BoxDecoration( | ||||
|                   borderRadius: BorderRadius.circular(4), | ||||
|                 ), | ||||
|               ), | ||||
|               menuItemStyleData: const MenuItemStyleData( | ||||
|                 height: 64, | ||||
|                 padding: EdgeInsets.only(left: 14, right: 14), | ||||
|               ), | ||||
|               iconStyleData: IconStyleData( | ||||
|                 icon: Icon(Icons.arrow_drop_down), | ||||
|                 iconSize: 19, | ||||
|                 iconEnabledColor: | ||||
|                     Theme.of(context).appBarTheme.foregroundColor!, | ||||
|                 iconDisabledColor: | ||||
|                     Theme.of(context).appBarTheme.foregroundColor!, | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|           const Gap(8), | ||||
|         ], | ||||
|       ), | ||||
|       body: developerStats.when( | ||||
|         data: | ||||
|             (stats) => SingleChildScrollView( | ||||
|               child: | ||||
|                   currentDeveloper.value == null | ||||
|                       ? Column( | ||||
|                         children: [ | ||||
|                           const Gap(24), | ||||
|                           const Icon(Symbols.info, size: 32).padding(bottom: 4), | ||||
|                           Text( | ||||
|                             'developerHubUnselectedHint', | ||||
|                             textAlign: TextAlign.center, | ||||
|                           ).tr(), | ||||
|                           const Gap(24), | ||||
|                           const Divider(height: 1), | ||||
|                           ...(developers.value?.map( | ||||
|                                 (developer) => ListTile( | ||||
|                                   leading: ProfilePictureWidget( | ||||
|                                     file: developer.picture, | ||||
|                                   ), | ||||
|                                   title: Text(developer.nick), | ||||
|                                   subtitle: Text('@${developer.name}'), | ||||
|                                   onTap: () { | ||||
|                                     currentDeveloper.value = developer; | ||||
|                                   }, | ||||
|                                 ), | ||||
|                               ) ?? | ||||
|                               []), | ||||
|                           ListTile( | ||||
|                             leading: const CircleAvatar( | ||||
|                               child: Icon(Symbols.add), | ||||
|                             ), | ||||
|                             title: Text('enrollDeveloper').tr(), | ||||
|                             subtitle: Text('enrollDeveloperHint').tr(), | ||||
|                             trailing: const Icon(Symbols.chevron_right), | ||||
|                             onTap: () { | ||||
|                               showModalBottomSheet( | ||||
|                                 context: context, | ||||
|                                 isScrollControlled: true, | ||||
|                                 builder: | ||||
|                                     (_) => const _DeveloperEnrollmentSheet(), | ||||
|                               ).then((value) { | ||||
|                                 if (value == true) { | ||||
|                                   ref.invalidate(developersProvider); | ||||
|                                 } | ||||
|                               }); | ||||
|                             }, | ||||
|                           ), | ||||
|                         ], | ||||
|                       ) | ||||
|                       : Column( | ||||
|                         children: [ | ||||
|                           if (stats != null) | ||||
|                             _DeveloperStatsWidget( | ||||
|                               stats: stats, | ||||
|                             ).padding(vertical: 12, horizontal: 12), | ||||
|                           ListTile( | ||||
|                             minTileHeight: 48, | ||||
|                             title: Text('customApps').tr(), | ||||
|                             trailing: Icon(Symbols.chevron_right), | ||||
|                             leading: const Icon(Symbols.apps), | ||||
|                             contentPadding: EdgeInsets.symmetric( | ||||
|                               horizontal: 24, | ||||
|                             ), | ||||
|                             onTap: () { | ||||
|                               context.push( | ||||
|                           '/developers/${currentDeveloper.value!.name}/apps', | ||||
|                         ); | ||||
|                             }, | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|             ), | ||||
|         loading: () => const Center(child: CircularProgressIndicator()), | ||||
|         error: | ||||
|             (err, stack) => ResponseErrorWidget( | ||||
|               error: err, | ||||
|               onRetry: () { | ||||
|                 ref.invalidate( | ||||
|                   developerStatsProvider(currentDeveloper.value?.name), | ||||
|                 ); | ||||
|               }, | ||||
|             ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _DeveloperStatsWidget extends StatelessWidget { | ||||
|   final DeveloperStats stats; | ||||
|   const _DeveloperStatsWidget({required this.stats}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return SingleChildScrollView( | ||||
|       child: Column( | ||||
|         spacing: 8, | ||||
|         children: [ | ||||
|           Row( | ||||
|             spacing: 8, | ||||
|             children: [ | ||||
|               Expanded( | ||||
|                 child: _buildStatsCard( | ||||
|                   context, | ||||
|                   stats.totalCustomApps.toString(), | ||||
|                   'totalCustomApps', | ||||
|                 ), | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   Widget _buildStatsCard( | ||||
|     BuildContext context, | ||||
|     String statValue, | ||||
|     String statLabel, | ||||
|   ) { | ||||
|     return Card( | ||||
|       margin: EdgeInsets.zero, | ||||
|       child: SizedBox( | ||||
|         height: 100, | ||||
|         child: Padding( | ||||
|           padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8), | ||||
|           child: Column( | ||||
|             crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|             mainAxisAlignment: MainAxisAlignment.center, | ||||
|             children: [ | ||||
|               Text( | ||||
|                 statValue, | ||||
|                 style: Theme.of(context).textTheme.headlineMedium, | ||||
|               ), | ||||
|               const Gap(4), | ||||
|               Text( | ||||
|                 statLabel, | ||||
|                 maxLines: 1, | ||||
|                 overflow: TextOverflow.ellipsis, | ||||
|               ).tr(), | ||||
|             ], | ||||
|           ), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _DeveloperEnrollmentSheet extends HookConsumerWidget { | ||||
|   const _DeveloperEnrollmentSheet(); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final publishers = ref.watch(publishersManagedProvider); | ||||
|  | ||||
|     Future<void> enroll(SnPublisher publisher) async { | ||||
|       try { | ||||
|         final client = ref.read(apiClientProvider); | ||||
|         await client.post('/developers/${publisher.name}/enroll'); | ||||
|         if (context.mounted) { | ||||
|           Navigator.pop(context, true); | ||||
|         } | ||||
|       } catch (err) { | ||||
|         showErrorAlert(err); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return SheetScaffold( | ||||
|       titleText: 'enrollDeveloper'.tr(), | ||||
|       child: publishers.when( | ||||
|         data: | ||||
|             (items) => | ||||
|                 items.isEmpty | ||||
|                     ? Center( | ||||
|                       child: | ||||
|                           Text( | ||||
|                             'noPublishersToEnroll', | ||||
|                             textAlign: TextAlign.center, | ||||
|                           ).tr(), | ||||
|                     ) | ||||
|                     : ListView.builder( | ||||
|                       shrinkWrap: true, | ||||
|                       itemCount: items.length, | ||||
|                       itemBuilder: (context, index) { | ||||
|                         final publisher = items[index]; | ||||
|                         return ListTile( | ||||
|                           leading: ProfilePictureWidget( | ||||
|                             fileId: publisher.picture?.id, | ||||
|                             fallbackIcon: Symbols.group, | ||||
|                           ), | ||||
|                           title: Text(publisher.nick), | ||||
|                           subtitle: Text('@${publisher.name}'), | ||||
|                           onTap: () => enroll(publisher), | ||||
|                         ); | ||||
|                       }, | ||||
|                     ), | ||||
|         loading: () => const Center(child: CircularProgressIndicator()), | ||||
|         error: | ||||
|             (error, _) => ResponseErrorWidget( | ||||
|               error: error, | ||||
|               onRetry: () => ref.invalidate(publishersManagedProvider), | ||||
|             ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										172
									
								
								lib/screens/developers/hub.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								lib/screens/developers/hub.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'hub.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$developerStatsHash() => r'783398cbde09c3d956c3e20b02a1cebd1f8ab748'; | ||||
|  | ||||
| /// Copied from Dart SDK | ||||
| class _SystemHash { | ||||
|   _SystemHash._(); | ||||
|  | ||||
|   static int combine(int hash, int value) { | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + value); | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | ||||
|     return hash ^ (hash >> 6); | ||||
|   } | ||||
|  | ||||
|   static int finish(int hash) { | ||||
|     // ignore: parameter_assignments | ||||
|     hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | ||||
|     // ignore: parameter_assignments | ||||
|     hash = hash ^ (hash >> 11); | ||||
|     return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /// See also [developerStats]. | ||||
| @ProviderFor(developerStats) | ||||
| const developerStatsProvider = DeveloperStatsFamily(); | ||||
|  | ||||
| /// See also [developerStats]. | ||||
| class DeveloperStatsFamily extends Family<AsyncValue<DeveloperStats?>> { | ||||
|   /// See also [developerStats]. | ||||
|   const DeveloperStatsFamily(); | ||||
|  | ||||
|   /// See also [developerStats]. | ||||
|   DeveloperStatsProvider call(String? uname) { | ||||
|     return DeveloperStatsProvider(uname); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   DeveloperStatsProvider getProviderOverride( | ||||
|     covariant DeveloperStatsProvider provider, | ||||
|   ) { | ||||
|     return call(provider.uname); | ||||
|   } | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||
|  | ||||
|   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||
|  | ||||
|   @override | ||||
|   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||
|       _allTransitiveDependencies; | ||||
|  | ||||
|   @override | ||||
|   String? get name => r'developerStatsProvider'; | ||||
| } | ||||
|  | ||||
| /// See also [developerStats]. | ||||
| class DeveloperStatsProvider | ||||
|     extends AutoDisposeFutureProvider<DeveloperStats?> { | ||||
|   /// See also [developerStats]. | ||||
|   DeveloperStatsProvider(String? uname) | ||||
|     : this._internal( | ||||
|         (ref) => developerStats(ref as DeveloperStatsRef, uname), | ||||
|         from: developerStatsProvider, | ||||
|         name: r'developerStatsProvider', | ||||
|         debugGetCreateSourceHash: | ||||
|             const bool.fromEnvironment('dart.vm.product') | ||||
|                 ? null | ||||
|                 : _$developerStatsHash, | ||||
|         dependencies: DeveloperStatsFamily._dependencies, | ||||
|         allTransitiveDependencies: | ||||
|             DeveloperStatsFamily._allTransitiveDependencies, | ||||
|         uname: uname, | ||||
|       ); | ||||
|  | ||||
|   DeveloperStatsProvider._internal( | ||||
|     super._createNotifier, { | ||||
|     required super.name, | ||||
|     required super.dependencies, | ||||
|     required super.allTransitiveDependencies, | ||||
|     required super.debugGetCreateSourceHash, | ||||
|     required super.from, | ||||
|     required this.uname, | ||||
|   }) : super.internal(); | ||||
|  | ||||
|   final String? uname; | ||||
|  | ||||
|   @override | ||||
|   Override overrideWith( | ||||
|     FutureOr<DeveloperStats?> Function(DeveloperStatsRef provider) create, | ||||
|   ) { | ||||
|     return ProviderOverride( | ||||
|       origin: this, | ||||
|       override: DeveloperStatsProvider._internal( | ||||
|         (ref) => create(ref as DeveloperStatsRef), | ||||
|         from: from, | ||||
|         name: null, | ||||
|         dependencies: null, | ||||
|         allTransitiveDependencies: null, | ||||
|         debugGetCreateSourceHash: null, | ||||
|         uname: uname, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   AutoDisposeFutureProviderElement<DeveloperStats?> createElement() { | ||||
|     return _DeveloperStatsProviderElement(this); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return other is DeveloperStatsProvider && other.uname == uname; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int get hashCode { | ||||
|     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||
|     hash = _SystemHash.combine(hash, uname.hashCode); | ||||
|  | ||||
|     return _SystemHash.finish(hash); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| mixin DeveloperStatsRef on AutoDisposeFutureProviderRef<DeveloperStats?> { | ||||
|   /// The parameter `uname` of this provider. | ||||
|   String? get uname; | ||||
| } | ||||
|  | ||||
| class _DeveloperStatsProviderElement | ||||
|     extends AutoDisposeFutureProviderElement<DeveloperStats?> | ||||
|     with DeveloperStatsRef { | ||||
|   _DeveloperStatsProviderElement(super.provider); | ||||
|  | ||||
|   @override | ||||
|   String? get uname => (origin as DeveloperStatsProvider).uname; | ||||
| } | ||||
|  | ||||
| String _$developersHash() => r'f52639d3c21aafbf235c8ae33f35448baf2989a1'; | ||||
|  | ||||
| /// See also [developers]. | ||||
| @ProviderFor(developers) | ||||
| final developersProvider = | ||||
|     AutoDisposeFutureProvider<List<SnPublisher>>.internal( | ||||
|       developers, | ||||
|       name: r'developersProvider', | ||||
|       debugGetCreateSourceHash: | ||||
|           const bool.fromEnvironment('dart.vm.product') | ||||
|               ? null | ||||
|               : _$developersHash, | ||||
|       dependencies: null, | ||||
|       allTransitiveDependencies: null, | ||||
|     ); | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| typedef DevelopersRef = AutoDisposeFutureProviderRef<List<SnPublisher>>; | ||||
| // ignore_for_file: type=lint | ||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||
							
								
								
									
										12
									
								
								lib/screens/developers/new_app.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/screens/developers/new_app.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:island/screens/developers/edit_app.dart'; | ||||
|  | ||||
| class NewCustomAppScreen extends StatelessWidget { | ||||
|   final String publisherName; | ||||
|   const NewCustomAppScreen({super.key, required this.publisherName}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return EditAppScreen(publisherName: publisherName); | ||||
|   } | ||||
| } | ||||
| @@ -6,6 +6,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/activity.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/models/realm.dart'; | ||||
| import 'package:island/pods/userinfo.dart'; | ||||
| import 'package:island/services/responsive.dart'; | ||||
|   | ||||
| @@ -4,19 +4,18 @@ import 'dart:math' as math; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/user.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/pods/websocket.dart'; | ||||
| import 'package:island/widgets/alert.dart'; | ||||
| import 'package:island/route.dart'; | ||||
| import 'package:island/widgets/app_scaffold.dart'; | ||||
| import 'package:island/widgets/content/markdown.dart'; | ||||
| import 'package:relative_time/relative_time.dart'; | ||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||
| import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||
| import 'package:styled_widget/styled_widget.dart'; | ||||
| import 'package:url_launcher/url_launcher.dart'; | ||||
| import 'package:url_launcher/url_launcher_string.dart'; | ||||
|  | ||||
| part 'notification.g.dart'; | ||||
|  | ||||
| @@ -180,36 +179,17 @@ class NotificationScreen extends HookConsumerWidget { | ||||
|                             ), | ||||
|                           ), | ||||
|                   onTap: () { | ||||
|                     if (notification.meta['link'] is String) { | ||||
|                       final href = notification.meta['link']; | ||||
|                       final uri = Uri.tryParse(href); | ||||
|                       if (uri == null) { | ||||
|                         showSnackBar( | ||||
|                           'brokenLink'.tr(args: []), | ||||
|                           action: SnackBarAction( | ||||
|                             label: 'copyToClipboard'.tr(), | ||||
|                             onPressed: () { | ||||
|                               Clipboard.setData(ClipboardData(text: href)); | ||||
|                               clearSnackBar(context); | ||||
|                             }, | ||||
|                           ), | ||||
|                     if (notification.meta['action_uri'] != null) { | ||||
|                       var uri = notification.meta['action_uri'] as String; | ||||
|                       if (uri.startsWith('/')) { | ||||
|                         // In-app routes | ||||
|                         rootNavigatorKey.currentContext?.push( | ||||
|                           notification.meta['action_uri'], | ||||
|                         ); | ||||
|                         return; | ||||
|                       } else { | ||||
|                         // External URLs | ||||
|                         launchUrlString(uri); | ||||
|                       } | ||||
|                       if (uri.scheme == 'solian') { | ||||
|                         context.push( | ||||
|                           ['', uri.host, ...uri.pathSegments].join('/'), | ||||
|                         ); | ||||
|                         return; | ||||
|                       } | ||||
|                       showConfirmAlert( | ||||
|                         'openLinkConfirmDescription'.tr(args: [href]), | ||||
|                         'openLinkConfirm'.tr(), | ||||
|                       ).then((value) { | ||||
|                         if (value) { | ||||
|                           launchUrl(uri, mode: LaunchMode.externalApplication); | ||||
|                         } | ||||
|                       }); | ||||
|                     } | ||||
|                   }, | ||||
|                 ); | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/models/user.dart'; | ||||
| import 'package:island/pods/config.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
|   | ||||
| @@ -400,7 +400,7 @@ class _PublisherSubscriptionStatusProviderElement | ||||
| } | ||||
|  | ||||
| String _$publisherAppbarForcegroundColorHash() => | ||||
|     r'3ff2eebb48d3f3af1907052f471e648f5b14b13c'; | ||||
|     r'd781a806a242aea5c1609ec98c97c52fdd9f7db1'; | ||||
|  | ||||
| /// See also [publisherAppbarForcegroundColor]. | ||||
| @ProviderFor(publisherAppbarForcegroundColor) | ||||
|   | ||||
| @@ -294,9 +294,9 @@ class EditRealmScreen extends HookConsumerWidget { | ||||
|                     child: | ||||
|                         background.value != null | ||||
|                             ? CloudFileWidget( | ||||
|                                 item: background.value!, | ||||
|                                 fit: BoxFit.cover, | ||||
|                               ) | ||||
|                               item: background.value!, | ||||
|                               fit: BoxFit.cover, | ||||
|                             ) | ||||
|                             : const SizedBox.shrink(), | ||||
|                   ), | ||||
|                   onTap: () { | ||||
| @@ -351,17 +351,36 @@ class EditRealmScreen extends HookConsumerWidget { | ||||
|                       (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||
|                 ), | ||||
|                 const SizedBox(height: 16), | ||||
|                 CheckboxListTile( | ||||
|                   title: const Text('isPublic').tr(), | ||||
|                   subtitle: const Text('isPublicHint').tr(), | ||||
|                   value: isPublic.value, | ||||
|                   onChanged: (value) => isPublic.value = value ?? false, | ||||
|                 ), | ||||
|                 CheckboxListTile( | ||||
|                   title: const Text('isCommunity').tr(), | ||||
|                   subtitle: const Text('isCommunityHint').tr(), | ||||
|                   value: isCommunity.value, | ||||
|                   onChanged: (value) => isCommunity.value = value ?? false, | ||||
|                 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( | ||||
| @@ -435,47 +454,47 @@ class _RealmInviteSheet extends HookConsumerWidget { | ||||
|             (items) => | ||||
|                 items.isEmpty | ||||
|                     ? Center( | ||||
|                         child: | ||||
|                             Text( | ||||
|                               'invitesEmpty', | ||||
|                               textAlign: TextAlign.center, | ||||
|                             ).tr(), | ||||
|                       ) | ||||
|                       child: | ||||
|                           Text( | ||||
|                             'invitesEmpty', | ||||
|                             textAlign: TextAlign.center, | ||||
|                           ).tr(), | ||||
|                     ) | ||||
|                     : ListView.builder( | ||||
|                         shrinkWrap: true, | ||||
|                         itemCount: items.length, | ||||
|                         itemBuilder: (context, index) { | ||||
|                           final invite = items[index]; | ||||
|                           return ListTile( | ||||
|                             leading: ProfilePictureWidget( | ||||
|                               fileId: invite.realm!.picture?.id, | ||||
|                               fallbackIcon: Symbols.group, | ||||
|                             ), | ||||
|                             title: Text(invite.realm!.name), | ||||
|                             subtitle: | ||||
|                                 Text( | ||||
|                                   invite.role >= 100 | ||||
|                                       ? 'permissionOwner' | ||||
|                                       : invite.role >= 50 | ||||
|                                       ? 'permissionModerator' | ||||
|                                       : 'permissionMember', | ||||
|                                 ).tr(), | ||||
|                             trailing: Row( | ||||
|                               mainAxisSize: MainAxisSize.min, | ||||
|                               children: [ | ||||
|                                 IconButton( | ||||
|                                   icon: const Icon(Symbols.check), | ||||
|                                   onPressed: () => acceptInvite(invite), | ||||
|                                 ), | ||||
|                                 IconButton( | ||||
|                                   icon: const Icon(Symbols.close), | ||||
|                                   onPressed: () => declineInvite(invite), | ||||
|                                 ), | ||||
|                               ], | ||||
|                             ), | ||||
|                           ); | ||||
|                         }, | ||||
|                       ), | ||||
|                       shrinkWrap: true, | ||||
|                       itemCount: items.length, | ||||
|                       itemBuilder: (context, index) { | ||||
|                         final invite = items[index]; | ||||
|                         return ListTile( | ||||
|                           leading: ProfilePictureWidget( | ||||
|                             fileId: invite.realm!.picture?.id, | ||||
|                             fallbackIcon: Symbols.group, | ||||
|                           ), | ||||
|                           title: Text(invite.realm!.name), | ||||
|                           subtitle: | ||||
|                               Text( | ||||
|                                 invite.role >= 100 | ||||
|                                     ? 'permissionOwner' | ||||
|                                     : invite.role >= 50 | ||||
|                                     ? 'permissionModerator' | ||||
|                                     : 'permissionMember', | ||||
|                               ).tr(), | ||||
|                           trailing: Row( | ||||
|                             mainAxisSize: MainAxisSize.min, | ||||
|                             children: [ | ||||
|                               IconButton( | ||||
|                                 icon: const Icon(Symbols.check), | ||||
|                                 onPressed: () => acceptInvite(invite), | ||||
|                               ), | ||||
|                               IconButton( | ||||
|                                 icon: const Icon(Symbols.close), | ||||
|                                 onPressed: () => declineInvite(invite), | ||||
|                               ), | ||||
|                             ], | ||||
|                           ), | ||||
|                         ); | ||||
|                       }, | ||||
|                     ), | ||||
|         loading: () => const Center(child: CircularProgressIndicator()), | ||||
|         error: | ||||
|             (error, _) => ResponseErrorWidget( | ||||
|   | ||||
| @@ -341,6 +341,25 @@ class SettingsScreen extends HookConsumerWidget { | ||||
|     ]; | ||||
|  | ||||
|     final behaviorSettings = [ | ||||
|       ListTile( | ||||
|         minLeadingWidth: 48, | ||||
|         title: Text('creatorHub').tr(), | ||||
|         contentPadding: const EdgeInsets.only(left: 24, right: 17), | ||||
|         leading: const Icon(Symbols.rocket_launch), | ||||
|         trailing: const Icon(Symbols.chevron_right), | ||||
|         onTap: () => context.push('/creators'), | ||||
|       ), | ||||
|  | ||||
|       // Developer Hub | ||||
|       ListTile( | ||||
|         minLeadingWidth: 48, | ||||
|         title: Text('developerHub').tr(), | ||||
|         contentPadding: const EdgeInsets.only(left: 24, right: 17), | ||||
|         leading: const Icon(Symbols.hub), | ||||
|         trailing: const Icon(Symbols.chevron_right), | ||||
|         onTap: () => context.push('/developers'), | ||||
|       ), | ||||
|  | ||||
|       // Auto translate settings | ||||
|       ListTile( | ||||
|         minLeadingWidth: 48, | ||||
|   | ||||
| @@ -44,7 +44,7 @@ class AudioCallButton extends HookConsumerWidget { | ||||
|       try { | ||||
|         await apiClient.post('/chat/realtime/$roomId'); | ||||
|         if (context.mounted) { | ||||
|           context.push('/chat/call/roomId'); | ||||
|           context.push('/chat/call/$roomId'); | ||||
|         } | ||||
|       } catch (e) { | ||||
|         showErrorAlert(e); | ||||
| @@ -96,7 +96,7 @@ class AudioCallButton extends HookConsumerWidget { | ||||
|         tooltip: 'Join Ongoing Call', | ||||
|         onPressed: () { | ||||
|           if (context.mounted) { | ||||
|             context.push('/chat/call/roomId'); | ||||
|             context.push('/chat/$roomId/call'); | ||||
|           } | ||||
|         }, | ||||
|       ); | ||||
|   | ||||
| @@ -125,6 +125,7 @@ class CloudFileList extends HookConsumerWidget { | ||||
|               if (!disableZoomIn) { | ||||
|                 context.pushTransparentRoute( | ||||
|                   CloudFileZoomIn(item: files[i], heroTag: heroTags[i]), | ||||
|                   rootNavigator: true, | ||||
|                 ); | ||||
|               } | ||||
|             }, | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:image_picker/image_picker.dart'; | ||||
| import 'package:island/models/file.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/pods/config.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/services/file.dart'; | ||||
|   | ||||
| @@ -362,6 +362,7 @@ class PostItem extends HookConsumerWidget { | ||||
|                           showModalBottomSheet( | ||||
|                             context: context, | ||||
|                             isScrollControlled: true, | ||||
|                             useRootNavigator: true, | ||||
|                             builder: (context) => PostRepliesSheet(post: item), | ||||
|                           ); | ||||
|                         } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/screens/creators/publishers.dart'; | ||||
| import 'package:island/widgets/alert.dart'; | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/models/publisher.dart'; | ||||
| import 'package:island/widgets/content/cloud_files.dart'; | ||||
|  | ||||
| class PublisherCard extends ConsumerWidget { | ||||
|   | ||||
| @@ -11,7 +11,6 @@ import 'package:island/models/file.dart'; | ||||
| import 'package:island/pods/link_preview.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/pods/config.dart'; | ||||
| import 'package:island/pods/userinfo.dart'; | ||||
| import 'package:island/services/file.dart'; | ||||
| import 'package:mime/mime.dart'; | ||||
|  | ||||
| @@ -193,7 +192,6 @@ class _ShareSheetState extends ConsumerState<ShareSheet> { | ||||
|     setState(() => _isLoading = true); | ||||
|     try { | ||||
|       final apiClient = ref.read(apiClientProvider); | ||||
|       final userInfo = ref.read(userInfoProvider.notifier); | ||||
|       final serverUrl = ref.read(serverUrlProvider); | ||||
|  | ||||
|       String content = _messageController.text.trim(); | ||||
| @@ -218,7 +216,7 @@ class _ShareSheetState extends ConsumerState<ShareSheet> { | ||||
|         case ShareContentType.file: | ||||
|           // Upload files to cloud storage | ||||
|           if (widget.content.files?.isNotEmpty == true) { | ||||
|             final token = await userInfo.getAccessToken(); | ||||
|             final token = ref.watch(tokenProvider)?.token; | ||||
|             if (token == null) { | ||||
|               throw Exception('Authentication required'); | ||||
|             } | ||||
|   | ||||
| @@ -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.0.0+108 | ||||
| version: 3.0.0+109 | ||||
|  | ||||
| environment: | ||||
|   sdk: ^3.7.2 | ||||
| @@ -123,7 +123,7 @@ dependencies: | ||||
|   receive_sharing_intent: ^1.8.1 | ||||
|   top_snackbar_flutter: ^3.3.0 | ||||
|   textfield_tags: | ||||
|    git: | ||||
|     git: | ||||
|       url: https://github.com/lionelmennig/textfield_tags.git | ||||
|       ref: fixes/allow-controller-re-registration | ||||
|   mime: ^2.0.0 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user