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:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- "*"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@ -59,6 +59,7 @@ jobs:
|
|||||||
sudo apt-get install -y libnotify-dev
|
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 libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||||
sudo apt-get install -y gstreamer-1.0
|
sudo apt-get install -y gstreamer-1.0
|
||||||
|
sudo apt-get install -y libsecret-1-0
|
||||||
- run: flutter pub get
|
- run: flutter pub get
|
||||||
- run: flutter build linux
|
- run: flutter build linux
|
||||||
- name: Archive production artifacts
|
- name: Archive production artifacts
|
||||||
@ -80,4 +81,4 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-output-linux-appimage
|
name: build-output-linux-appimage
|
||||||
path: './*.AppImage*'
|
path: "./*.AppImage*"
|
||||||
|
@ -98,7 +98,7 @@
|
|||||||
<receiver
|
<receiver
|
||||||
android:name=".receiver.ReplyReceiver"
|
android:name=".receiver.ReplyReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false" />
|
android:exported="true" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.MessagingService"
|
android:name=".service.MessagingService"
|
||||||
|
@ -1,14 +1,39 @@
|
|||||||
package dev.solsynth.solian
|
package dev.solsynth.solian
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import io.flutter.plugins.sharedpreferences.LegacySharedPreferencesPlugin
|
import io.flutter.plugins.sharedpreferences.LegacySharedPreferencesPlugin
|
||||||
|
|
||||||
class MainActivity : FlutterActivity()
|
class MainActivity : FlutterActivity()
|
||||||
{
|
{
|
||||||
|
private val CHANNEL = "dev.solsynth.solian/notifications"
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
// https://github.com/flutter/flutter/issues/153075#issuecomment-2693189362
|
// https://github.com/flutter/flutter/issues/153075#issuecomment-2693189362
|
||||||
flutterEngine.plugins.add(LegacySharedPreferencesPlugin())
|
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,48 +1,47 @@
|
|||||||
package dev.solsynth.solian.network
|
package dev.solsynth.solian.network
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import okhttp3.*
|
import android.content.SharedPreferences
|
||||||
|
import okhttp3.Call
|
||||||
|
import okhttp3.Callback
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import okhttp3.Response
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
class ApiClient(private val context: Context) {
|
class ApiClient(private val context: Context) {
|
||||||
private val client = OkHttpClient()
|
private val client = OkHttpClient()
|
||||||
|
private val sharedPreferences: SharedPreferences = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
fun sendMessage(roomId: String, content: String, repliedMessageId: String, callback: () -> Unit) {
|
fun sendMessage(roomId: String, message: String, replyTo: String, callback: (Boolean) -> Unit) {
|
||||||
val prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
|
val token = sharedPreferences.getString("flutter.token", null)
|
||||||
val token = prefs.getString("flutter.token", null)
|
if (token == null) {
|
||||||
val serverUrl = prefs.getString("flutter.serverUrl", null)
|
callback(false)
|
||||||
|
|
||||||
if (token == null || serverUrl == null) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val url = "$serverUrl/chat/$roomId/messages"
|
val json = JSONObject().apply {
|
||||||
|
put("content", message)
|
||||||
val json = JSONObject()
|
put("reply_to", replyTo)
|
||||||
json.put("content", content)
|
}
|
||||||
json.put("replied_message_id", repliedMessageId)
|
val body = json.toString().toRequestBody("application/json; charset=utf-8".toMediaType())
|
||||||
|
|
||||||
val requestBody = json.toString().toRequestBody("application/json; charset=utf-8".toMediaType())
|
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(url)
|
.url("https://solian.dev/api/rooms/$roomId/messages")
|
||||||
.post(requestBody)
|
.header("Authorization", "Bearer $token")
|
||||||
.addHeader("Authorization", "AtField $token")
|
.post(body)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
client.newCall(request).enqueue(object : Callback {
|
client.newCall(request).enqueue(object : Callback {
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
// Handle failure
|
callback(false)
|
||||||
callback()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
// Handle success
|
callback(response.isSuccessful)
|
||||||
callback()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -72,6 +72,7 @@ class MessagingService: FirebaseMessagingService() {
|
|||||||
|
|
||||||
val intent = Intent(this, MainActivity::class.java)
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
intent.putExtra("room_id", roomId)
|
||||||
val pendingIntent = PendingIntent.getActivity(this, 0, intent, pendingIntentFlags)
|
val pendingIntent = PendingIntent.getActivity(this, 0, intent, pendingIntentFlags)
|
||||||
|
|
||||||
val notificationBuilder = NotificationCompat.Builder(this, "messages")
|
val notificationBuilder = NotificationCompat.Builder(this, "messages")
|
||||||
|
@ -89,14 +89,32 @@
|
|||||||
"authFactorInAppNotifyDescription": "A one-time code sent via in-app notification.",
|
"authFactorInAppNotifyDescription": "A one-time code sent via in-app notification.",
|
||||||
"authFactorPin": "Pin Code",
|
"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.",
|
"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",
|
"explore": "Explore",
|
||||||
"exploreFilterSubscriptions": "Subscriptions",
|
"exploreFilterSubscriptions": "Subscriptions",
|
||||||
"exploreFilterFriends": "Friends",
|
"exploreFilterFriends": "Friends",
|
||||||
"discover": "Discover",
|
"discover": "Discover",
|
||||||
|
"joinRealm": "Join Realm",
|
||||||
"account": "Account",
|
"account": "Account",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"slug": "Slug",
|
"slug": "Slug",
|
||||||
"slugHint": "The slug will be used in the URL to access this resource, it should be unique and URL safe.",
|
"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...",
|
"loading": "Loading...",
|
||||||
"descriptionNone": "No description yet.",
|
"descriptionNone": "No description yet.",
|
||||||
"invites": "Invites",
|
"invites": "Invites",
|
||||||
@ -231,6 +249,7 @@
|
|||||||
"uploadingProgress": "Uploading {} of {}",
|
"uploadingProgress": "Uploading {} of {}",
|
||||||
"uploadAll": "Upload All",
|
"uploadAll": "Upload All",
|
||||||
"stickerCopyPlaceholder": "Copy Placeholder",
|
"stickerCopyPlaceholder": "Copy Placeholder",
|
||||||
|
"realmSelection": "Select a Realm",
|
||||||
"individual": "Individual",
|
"individual": "Individual",
|
||||||
"firstPostBadgeName": "First Post",
|
"firstPostBadgeName": "First Post",
|
||||||
"firstPostBadgeDescription": "Created your first post on Solar Network",
|
"firstPostBadgeDescription": "Created your first post on Solar Network",
|
||||||
@ -286,6 +305,12 @@
|
|||||||
"levelingProgressExperience": "{} EXP",
|
"levelingProgressExperience": "{} EXP",
|
||||||
"levelingProgressLevel": "Level {}",
|
"levelingProgressLevel": "Level {}",
|
||||||
"fileUploadingProgress": "Uploading file #{}: {}%",
|
"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",
|
"memberRole": "Member Role",
|
||||||
"memberRoleHint": "Greater number has higher permission.",
|
"memberRoleHint": "Greater number has higher permission.",
|
||||||
"memberRoleEdit": "Edit role for @{}",
|
"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.",
|
"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...",
|
"brokenLink": "Unable open link {}... It might be broken or missing uri parts...",
|
||||||
"copyToClipboard": "Copy to clipboard",
|
"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",
|
"walletNotFound": "Wallet not found",
|
||||||
"walletCreateHint": "You don't have a wallet yet. Create one to start using the Solar Network eWallet.",
|
"walletCreateHint": "You don't have a wallet yet. Create one to start using the Solar Network eWallet.",
|
||||||
"walletCreate": "Create a Wallet",
|
"walletCreate": "Create a Wallet",
|
||||||
@ -304,6 +333,12 @@
|
|||||||
"settingsBackgroundImageClear": "Clear Background Image",
|
"settingsBackgroundImageClear": "Clear Background Image",
|
||||||
"settingsBackgroundGenerateColor": "Generate color scheme from Bacground Image",
|
"settingsBackgroundGenerateColor": "Generate color scheme from Bacground Image",
|
||||||
"messageNone": "No content to display",
|
"messageNone": "No content to display",
|
||||||
|
"unreadMessages": {
|
||||||
|
"one": "{} unread message",
|
||||||
|
"other": "{} unread messages"
|
||||||
|
},
|
||||||
|
"chatBreakNone": "None",
|
||||||
|
"settingsRealmCompactView": "Compact Realm View",
|
||||||
"settingsMixedFeed": "Mixed Feed",
|
"settingsMixedFeed": "Mixed Feed",
|
||||||
"settingsAutoTranslate": "Auto Translate",
|
"settingsAutoTranslate": "Auto Translate",
|
||||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||||
@ -346,6 +381,7 @@
|
|||||||
"postVisibilityUnlisted": "Unlisted",
|
"postVisibilityUnlisted": "Unlisted",
|
||||||
"postVisibilityPrivate": "Private",
|
"postVisibilityPrivate": "Private",
|
||||||
"postTruncated": "Content truncated, tap to view full post",
|
"postTruncated": "Content truncated, tap to view full post",
|
||||||
|
"copyMessage": "Copy Message",
|
||||||
"authFactor": "Authentication Factor",
|
"authFactor": "Authentication Factor",
|
||||||
"authFactorDelete": "Delete the Factor",
|
"authFactorDelete": "Delete the Factor",
|
||||||
"authFactorDeleteHint": "Are you sure you want to delete this authentication factor? This action cannot be undone.",
|
"authFactorDeleteHint": "Are you sure you want to delete this authentication factor? This action cannot be undone.",
|
||||||
@ -373,6 +409,10 @@
|
|||||||
"lastActiveAt": "Last active at {}",
|
"lastActiveAt": "Last active at {}",
|
||||||
"authDeviceLogout": "Logout",
|
"authDeviceLogout": "Logout",
|
||||||
"authDeviceLogoutHint": "Are you sure you want to logout this device? This will also disable the push notification to this device.",
|
"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",
|
"authDeviceEditLabel": "Edit Label",
|
||||||
"authDeviceLabelTitle": "Edit Device Label",
|
"authDeviceLabelTitle": "Edit Device Label",
|
||||||
"authDeviceLabelHint": "Enter a name for this device",
|
"authDeviceLabelHint": "Enter a name for this device",
|
||||||
@ -439,6 +479,21 @@
|
|||||||
"contactMethodSetPrimary": "Set as Primary",
|
"contactMethodSetPrimary": "Set as Primary",
|
||||||
"contactMethodSetPrimaryHint": "Set this contact method as your primary contact method for account recovery and notifications",
|
"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.",
|
"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",
|
"firstName": "First Name",
|
||||||
"middleName": "Middle Name",
|
"middleName": "Middle Name",
|
||||||
"lastName": "Last Name",
|
"lastName": "Last Name",
|
||||||
@ -520,17 +575,29 @@
|
|||||||
"quickActions": "Quick Actions",
|
"quickActions": "Quick Actions",
|
||||||
"post": "Post",
|
"post": "Post",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
|
"sendToChat": "Send to Chat",
|
||||||
"failedToShareToPost": "Failed to share to post: {}",
|
"failedToShareToPost": "Failed to share to post: {}",
|
||||||
"shareToChatComingSoon": "Share to chat functionality coming soon",
|
"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",
|
"systemShareComingSoon": "System share functionality coming soon",
|
||||||
"failedToShareToSystem": "Failed to share to system: {}",
|
"failedToShareToSystem": "Failed to share to system: {}",
|
||||||
"failedToCopy": "Failed to copy: {}",
|
"failedToCopy": "Failed to copy: {}",
|
||||||
|
"noChatRoomsAvailable": "No chat rooms available",
|
||||||
|
"failedToLoadChats": "Failed to load chats",
|
||||||
"contentToShare": "Content to share:",
|
"contentToShare": "Content to share:",
|
||||||
|
"unknownChat": "Unknown Chat",
|
||||||
|
"addAdditionalMessage": "Add additional message...",
|
||||||
"uploadingFiles": "Uploading files...",
|
"uploadingFiles": "Uploading files...",
|
||||||
|
"sharedSuccessfully": "Shared successfully!",
|
||||||
"shareSuccess": "Shared successfully!",
|
"shareSuccess": "Shared successfully!",
|
||||||
|
"shareToSpecificChatSuccess": "Shared to {} successfully!",
|
||||||
"wouldYouLikeToGoToChat": "Would you like to go to the chat?",
|
"wouldYouLikeToGoToChat": "Would you like to go to the chat?",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
|
"navigateToChat": "Navigate to Chat",
|
||||||
|
"wouldYouLikeToNavigateToChat": "Would you like to navigate to the chat?",
|
||||||
"abuseReport": "Report",
|
"abuseReport": "Report",
|
||||||
"abuseReportTitle": "Report Content",
|
"abuseReportTitle": "Report Content",
|
||||||
"abuseReportDescription": "Help us keep the community safe by reporting inappropriate content or behavior.",
|
"abuseReportDescription": "Help us keep the community safe by reporting inappropriate content or behavior.",
|
||||||
@ -564,5 +631,24 @@
|
|||||||
"realmJoinSuccess": "Successfully joined the realm.",
|
"realmJoinSuccess": "Successfully joined the realm.",
|
||||||
"discoverRealms": "Discover Realms",
|
"discoverRealms": "Discover Realms",
|
||||||
"discoverPublishers": "Discover Publishers",
|
"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:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker_android/image_picker_android.dart';
|
import 'package:image_picker_android/image_picker_android.dart';
|
||||||
@ -158,6 +159,28 @@ class IslandApp extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() {
|
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.
|
// When the app is opened from a terminated state.
|
||||||
FirebaseMessaging.instance.getInitialMessage().then((message) {
|
FirebaseMessaging.instance.getInitialMessage().then((message) {
|
||||||
if (message != null) {
|
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/file.dart';
|
||||||
import 'package:island/models/post_category.dart';
|
import 'package:island/models/post_category.dart';
|
||||||
import 'package:island/models/post_tag.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.freezed.dart';
|
||||||
part 'post.g.dart';
|
part 'post.g.dart';
|
||||||
@ -32,7 +32,7 @@ sealed class SnPost with _$SnPost {
|
|||||||
String? forwardedPostId,
|
String? forwardedPostId,
|
||||||
SnPost? forwardedPost,
|
SnPost? forwardedPost,
|
||||||
@Default([]) List<SnCloudFile> attachments,
|
@Default([]) List<SnCloudFile> attachments,
|
||||||
@Default(SnPublisher()) SnPublisher publisher,
|
required SnPublisher publisher,
|
||||||
@Default({}) Map<String, int> reactionsCount,
|
@Default({}) Map<String, int> reactionsCount,
|
||||||
@Default([]) List<dynamic> reactions,
|
@Default([]) List<dynamic> reactions,
|
||||||
@Default([]) List<PostTag> tags,
|
@Default([]) List<PostTag> tags,
|
||||||
@ -47,29 +47,6 @@ sealed class SnPost with _$SnPost {
|
|||||||
factory SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
|
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
|
@freezed
|
||||||
sealed class SnPublisherStats with _$SnPublisherStats {
|
sealed class SnPublisherStats with _$SnPublisherStats {
|
||||||
const factory SnPublisherStats({
|
const factory SnPublisherStats({
|
||||||
|
@ -156,7 +156,7 @@ $SnPublisherCopyWith<$Res> get publisher {
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnPost implements SnPost {
|
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);
|
factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@ -195,7 +195,7 @@ class _SnPost implements SnPost {
|
|||||||
return EqualUnmodifiableListView(_attachments);
|
return EqualUnmodifiableListView(_attachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override@JsonKey() final SnPublisher publisher;
|
@override final SnPublisher publisher;
|
||||||
final Map<String, int> _reactionsCount;
|
final Map<String, int> _reactionsCount;
|
||||||
@override@JsonKey() Map<String, int> get reactionsCount {
|
@override@JsonKey() Map<String, int> get reactionsCount {
|
||||||
if (_reactionsCount is EqualUnmodifiableMapView) return _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
|
/// @nodoc
|
||||||
mixin _$SnPublisherStats {
|
mixin _$SnPublisherStats {
|
||||||
|
|
||||||
|
@ -48,10 +48,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
|
|||||||
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
|
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
const [],
|
const [],
|
||||||
publisher:
|
publisher: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
|
||||||
json['publisher'] == null
|
|
||||||
? const SnPublisher()
|
|
||||||
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
|
|
||||||
reactionsCount:
|
reactionsCount:
|
||||||
(json['reactions_count'] as Map<String, dynamic>?)?.map(
|
(json['reactions_count'] as Map<String, dynamic>?)?.map(
|
||||||
(k, e) => MapEntry(k, (e as num).toInt()),
|
(k, e) => MapEntry(k, (e as num).toInt()),
|
||||||
@ -119,64 +116,6 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
|
|||||||
'is_truncated': instance.isTruncated,
|
'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 _$SnPublisherStatsFromJson(Map<String, dynamic> json) =>
|
||||||
_SnPublisherStats(
|
_SnPublisherStats(
|
||||||
postsCreated: (json['posts_created'] as num).toInt(),
|
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:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:island/models/file.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.freezed.dart';
|
||||||
part 'sticker.g.dart';
|
part 'sticker.g.dart';
|
||||||
|
@ -11,11 +11,6 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> {
|
|||||||
|
|
||||||
UserInfoNotifier(this._ref) : super(const AsyncValue.data(null));
|
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 {
|
Future<void> fetchUser() async {
|
||||||
try {
|
try {
|
||||||
final client = _ref.read(apiClientProvider);
|
final client = _ref.read(apiClientProvider);
|
||||||
|
120
lib/route.dart
120
lib/route.dart
@ -1,6 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/widgets/app_wrapper.dart';
|
||||||
import 'package:island/screens/tabs.dart';
|
import 'package:island/screens/tabs.dart';
|
||||||
|
|
||||||
@ -79,33 +83,37 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
return EventCalanderScreen(name: name);
|
return EventCalanderScreen(name: name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
ShellRoute(
|
||||||
path: '/creators',
|
builder:
|
||||||
builder: (context, state) => const CreatorHubScreen(),
|
(context, state, child) => CreatorHubShellScreen(child: child),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/posts',
|
path: '/creators',
|
||||||
|
builder: (context, state) => const CreatorHubScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/creators/:name/posts',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
return CreatorPostListScreen(pubName: name);
|
return CreatorPostListScreen(pubName: name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/stickers',
|
path: '/creators/:name/stickers',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
return StickersScreen(pubName: name);
|
return StickersScreen(pubName: name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/stickers/new',
|
path: '/creators/:name/stickers/new',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
return NewStickerPacksScreen(pubName: name);
|
return NewStickerPacksScreen(pubName: name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/stickers/:packId/edit',
|
path: '/creators/:name/stickers/:packId/edit',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
final packId = state.pathParameters['packId']!;
|
final packId = state.pathParameters['packId']!;
|
||||||
@ -113,7 +121,7 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/stickers/:packId',
|
path: '/creators/:name/stickers/:packId',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
final packId = state.pathParameters['packId']!;
|
final packId = state.pathParameters['packId']!;
|
||||||
@ -121,14 +129,14 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/stickers/:packId/new',
|
path: '/creators/:name/stickers/:packId/new',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final packId = state.pathParameters['packId']!;
|
final packId = state.pathParameters['packId']!;
|
||||||
return NewStickersScreen(packId: packId);
|
return NewStickersScreen(packId: packId);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/stickers/:packId/:id/edit',
|
path: '/creators/:name/stickers/:packId/:id/edit',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final packId = state.pathParameters['packId']!;
|
final packId = state.pathParameters['packId']!;
|
||||||
final id = state.pathParameters['id']!;
|
final id = state.pathParameters['id']!;
|
||||||
@ -136,11 +144,11 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'new',
|
path: '/creators/new',
|
||||||
builder: (context, state) => const NewPublisherScreen(),
|
builder: (context, state) => const NewPublisherScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name/edit',
|
path: '/creators/:name/edit',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
return EditPublisherScreen(name: 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
|
// Auth routes
|
||||||
GoRoute(
|
GoRoute(
|
||||||
@ -173,56 +211,64 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
},
|
},
|
||||||
routes: [
|
routes: [
|
||||||
// Explore tab
|
// Explore tab
|
||||||
GoRoute(
|
ShellRoute(
|
||||||
path: '/',
|
builder:
|
||||||
builder: (context, state) => const ExploreScreen(),
|
(context, state, child) => ExploreShellScreen(child: child),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'posts/:id',
|
path: '/',
|
||||||
|
builder: (context, state) => const ExploreScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/posts/:id',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final id = state.pathParameters['id']!;
|
final id = state.pathParameters['id']!;
|
||||||
return PostDetailScreen(id: id);
|
return PostDetailScreen(id: id);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'publishers/:name',
|
path: '/publishers/:name',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
return PublisherProfileScreen(name: name);
|
return PublisherProfileScreen(name: name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'discovery/realms',
|
path: '/discovery/realms',
|
||||||
builder: (context, state) => const DiscoveryRealmsScreen(),
|
builder: (context, state) => const DiscoveryRealmsScreen(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
// Chat tab
|
// Chat tab
|
||||||
GoRoute(
|
ShellRoute(
|
||||||
path: '/chat',
|
builder:
|
||||||
builder: (context, state) => const ChatListScreen(),
|
(context, state, child) => ChatShellScreen(child: child),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'new',
|
path: '/chat',
|
||||||
|
builder: (context, state) => const ChatListScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/chat/new',
|
||||||
builder: (context, state) => const NewChatScreen(),
|
builder: (context, state) => const NewChatScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':id',
|
path: '/chat/:id',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final id = state.pathParameters['id']!;
|
final id = state.pathParameters['id']!;
|
||||||
return ChatRoomScreen(id: id);
|
return ChatRoomScreen(id: id);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':id/edit',
|
path: '/chat/:id/edit',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final id = state.pathParameters['id']!;
|
final id = state.pathParameters['id']!;
|
||||||
return EditChatScreen(id: id);
|
return EditChatScreen(id: id);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':id/detail',
|
path: '/chat/:id/detail',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final id = state.pathParameters['id']!;
|
final id = state.pathParameters['id']!;
|
||||||
return ChatDetailScreen(id: id);
|
return ChatDetailScreen(id: id);
|
||||||
@ -258,39 +304,43 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Account tab
|
// Account tab
|
||||||
GoRoute(
|
ShellRoute(
|
||||||
path: '/account',
|
builder:
|
||||||
builder: (context, state) => const AccountScreen(),
|
(context, state, child) => AccountShellScreen(child: child),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'notifications',
|
path: '/account',
|
||||||
|
builder: (context, state) => const AccountScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/account/notifications',
|
||||||
builder: (context, state) => const NotificationScreen(),
|
builder: (context, state) => const NotificationScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'wallet',
|
path: '/account/wallet',
|
||||||
builder: (context, state) => const WalletScreen(),
|
builder: (context, state) => const WalletScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'relationships',
|
path: '/account/relationships',
|
||||||
builder: (context, state) => const RelationshipScreen(),
|
builder: (context, state) => const RelationshipScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ':name',
|
path: '/account/:name',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final name = state.pathParameters['name']!;
|
final name = state.pathParameters['name']!;
|
||||||
return AccountProfileScreen(name: name);
|
return AccountProfileScreen(name: name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'me/update',
|
path: '/account/me/update',
|
||||||
builder: (context, state) => const UpdateProfileScreen(),
|
builder: (context, state) => const UpdateProfileScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'me/leveling',
|
path: '/account/me/leveling',
|
||||||
builder: (context, state) => const LevelingScreen(),
|
builder: (context, state) => const LevelingScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'settings',
|
path: '/account/settings',
|
||||||
builder: (context, state) => const AccountSettingsScreen(),
|
builder: (context, state) => const AccountSettingsScreen(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -143,7 +143,7 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
progress: user.value!.profile.levelingProgress,
|
progress: user.value!.profile.levelingProgress,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.push('/account/leveling');
|
context.push('/account/me/leveling');
|
||||||
},
|
},
|
||||||
).padding(horizontal: 12),
|
).padding(horizontal: 12),
|
||||||
Row(
|
Row(
|
||||||
@ -178,7 +178,9 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
Text('developerPortalDescription').tr(),
|
Text('developerPortalDescription').tr(),
|
||||||
],
|
],
|
||||||
).padding(horizontal: 16, vertical: 12),
|
).padding(horizontal: 16, vertical: 12),
|
||||||
onTap: () {},
|
onTap: () {
|
||||||
|
context.push('/developers');
|
||||||
|
},
|
||||||
),
|
),
|
||||||
).height(140),
|
).height(140),
|
||||||
),
|
),
|
||||||
@ -210,7 +212,7 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
title: Text('wallet').tr(),
|
title: Text('wallet').tr(),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.push('/wallet');
|
context.push('/account/wallet');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
@ -53,17 +53,21 @@ Future<List<SnAccountBadge>> accountBadges(Ref ref, String uname) async {
|
|||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async {
|
Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async {
|
||||||
final account = await ref.watch(accountProvider(uname).future);
|
try {
|
||||||
if (account.profile.background == null) return null;
|
final account = await ref.watch(accountProvider(uname).future);
|
||||||
final palette = await PaletteGenerator.fromImageProvider(
|
if (account.profile.background == null) return null;
|
||||||
CloudImageWidget.provider(
|
final palette = await PaletteGenerator.fromImageProvider(
|
||||||
fileId: account.profile.background!.id,
|
CloudImageWidget.provider(
|
||||||
serverUrl: ref.watch(serverUrlProvider),
|
fileId: account.profile.background!.id,
|
||||||
),
|
serverUrl: ref.watch(serverUrlProvider),
|
||||||
);
|
),
|
||||||
final dominantColor = palette.dominantColor?.color;
|
);
|
||||||
if (dominantColor == null) return null;
|
final dominantColor = palette.dominantColor?.color;
|
||||||
return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
|
if (dominantColor == null) return null;
|
||||||
|
return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
|
@ -268,7 +268,7 @@ class _AccountBadgesProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$accountAppbarForcegroundColorHash() =>
|
String _$accountAppbarForcegroundColorHash() =>
|
||||||
r'f654a7a5594eda1500906e9ad023c22772257a9b';
|
r'8ee0cae10817b77fb09548a482f5247662b4374c';
|
||||||
|
|
||||||
/// See also [accountAppbarForcegroundColor].
|
/// See also [accountAppbarForcegroundColor].
|
||||||
@ProviderFor(accountAppbarForcegroundColor)
|
@ProviderFor(accountAppbarForcegroundColor)
|
||||||
|
@ -676,17 +676,36 @@ class EditChatScreen extends HookConsumerWidget {
|
|||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
CheckboxListTile(
|
Card(
|
||||||
title: const Text('isPublic').tr(),
|
margin: EdgeInsets.zero,
|
||||||
subtitle: const Text('isPublicHint').tr(),
|
child: Column(
|
||||||
value: isPublic.value,
|
children: [
|
||||||
onChanged: (value) => isPublic.value = value ?? false,
|
CheckboxListTile(
|
||||||
),
|
secondary: const Icon(Symbols.public),
|
||||||
CheckboxListTile(
|
title: Text('publicChat').tr(),
|
||||||
title: const Text('isCommunity').tr(),
|
subtitle: Text('publicChatDescription').tr(),
|
||||||
subtitle: const Text('isCommunityHint').tr(),
|
value: isPublic.value,
|
||||||
value: isCommunity.value,
|
onChanged: (value) {
|
||||||
onChanged: (value) => isCommunity.value = value ?? false,
|
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),
|
const SizedBox(height: 16),
|
||||||
Align(
|
Align(
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -6,14 +7,19 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
|
import 'package:island/models/publisher.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/screens/creators/publishers.dart';
|
import 'package:island/screens/creators/publishers.dart';
|
||||||
import 'package:island/services/responsive.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/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.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:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.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:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
part 'hub.g.dart';
|
part 'hub.g.dart';
|
||||||
@ -26,6 +32,65 @@ Future<SnPublisherStats?> publisherStats(Ref ref, String? uname) async {
|
|||||||
return SnPublisherStats.fromJson(resp.data);
|
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 {
|
class CreatorHubShellScreen extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const CreatorHubShellScreen({super.key, required this.child});
|
const CreatorHubShellScreen({super.key, required this.child});
|
||||||
@ -58,21 +123,20 @@ class CreatorHubScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final publishers = ref.watch(publishersManagedProvider);
|
final publishers = ref.watch(publishersManagedProvider);
|
||||||
|
final publisherInvites = ref.watch(publisherInvitesProvider);
|
||||||
final currentPublisher = useState<SnPublisher?>(
|
final currentPublisher = useState<SnPublisher?>(
|
||||||
publishers.value?.firstOrNull,
|
publishers.value?.firstOrNull,
|
||||||
);
|
);
|
||||||
|
|
||||||
void updatePublisher() {
|
void updatePublisher() {
|
||||||
context
|
context.push('/creators/${currentPublisher.value!.name}/edit').then((
|
||||||
.push('/creators/${currentPublisher.value!.name}/edit')
|
value,
|
||||||
.then((value) async {
|
) async {
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
final data = await ref.refresh(publishersManagedProvider.future);
|
final data = await ref.refresh(publishersManagedProvider.future);
|
||||||
currentPublisher.value =
|
currentPublisher.value =
|
||||||
data
|
data.where((e) => e.id == currentPublisher.value!.id).firstOrNull;
|
||||||
.where((e) => e.id == currentPublisher.value!.id)
|
});
|
||||||
.firstOrNull;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void deletePublisher() {
|
void deletePublisher() {
|
||||||
@ -126,6 +190,30 @@ class CreatorHubScreen extends HookConsumerWidget {
|
|||||||
leading: !isWide ? const PageBackButton() : null,
|
leading: !isWide ? const PageBackButton() : null,
|
||||||
title: Text('creatorHub').tr(),
|
title: Text('creatorHub').tr(),
|
||||||
actions: [
|
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(
|
DropdownButtonHideUnderline(
|
||||||
child: DropdownButton2<SnPublisher>(
|
child: DropdownButton2<SnPublisher>(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
@ -203,7 +291,7 @@ class CreatorHubScreen extends HookConsumerWidget {
|
|||||||
...(publishers.value?.map(
|
...(publishers.value?.map(
|
||||||
(publisher) => ListTile(
|
(publisher) => ListTile(
|
||||||
leading: ProfilePictureWidget(
|
leading: ProfilePictureWidget(
|
||||||
fileId: publisher.picture?.id,
|
file: publisher.picture,
|
||||||
),
|
),
|
||||||
title: Text(publisher.nick),
|
title: Text(publisher.nick),
|
||||||
subtitle: Text('@${publisher.name}'),
|
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),
|
Divider(height: 1).padding(vertical: 8),
|
||||||
ListTile(
|
ListTile(
|
||||||
minTileHeight: 48,
|
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? 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: 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
|
// 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:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:island/models/file.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/models/realm.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
import 'package:island/pods/network.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:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/models/activity.dart';
|
||||||
|
import 'package:island/models/publisher.dart';
|
||||||
import 'package:island/models/realm.dart';
|
import 'package:island/models/realm.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/pods/userinfo.dart';
|
||||||
import 'package:island/services/responsive.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:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/user.dart';
|
import 'package:island/models/user.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/websocket.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/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/markdown.dart';
|
import 'package:island/widgets/content/markdown.dart';
|
||||||
import 'package:relative_time/relative_time.dart';
|
import 'package:relative_time/relative_time.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||||
import 'package:styled_widget/styled_widget.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';
|
part 'notification.g.dart';
|
||||||
|
|
||||||
@ -180,36 +179,17 @@ class NotificationScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (notification.meta['link'] is String) {
|
if (notification.meta['action_uri'] != null) {
|
||||||
final href = notification.meta['link'];
|
var uri = notification.meta['action_uri'] as String;
|
||||||
final uri = Uri.tryParse(href);
|
if (uri.startsWith('/')) {
|
||||||
if (uri == null) {
|
// In-app routes
|
||||||
showSnackBar(
|
rootNavigatorKey.currentContext?.push(
|
||||||
'brokenLink'.tr(args: []),
|
notification.meta['action_uri'],
|
||||||
action: SnackBarAction(
|
|
||||||
label: 'copyToClipboard'.tr(),
|
|
||||||
onPressed: () {
|
|
||||||
Clipboard.setData(ClipboardData(text: href));
|
|
||||||
clearSnackBar(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
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:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
|
import 'package:island/models/publisher.dart';
|
||||||
import 'package:island/models/user.dart';
|
import 'package:island/models/user.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
|
@ -400,7 +400,7 @@ class _PublisherSubscriptionStatusProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$publisherAppbarForcegroundColorHash() =>
|
String _$publisherAppbarForcegroundColorHash() =>
|
||||||
r'3ff2eebb48d3f3af1907052f471e648f5b14b13c';
|
r'd781a806a242aea5c1609ec98c97c52fdd9f7db1';
|
||||||
|
|
||||||
/// See also [publisherAppbarForcegroundColor].
|
/// See also [publisherAppbarForcegroundColor].
|
||||||
@ProviderFor(publisherAppbarForcegroundColor)
|
@ProviderFor(publisherAppbarForcegroundColor)
|
||||||
|
@ -294,9 +294,9 @@ class EditRealmScreen extends HookConsumerWidget {
|
|||||||
child:
|
child:
|
||||||
background.value != null
|
background.value != null
|
||||||
? CloudFileWidget(
|
? CloudFileWidget(
|
||||||
item: background.value!,
|
item: background.value!,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
)
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -351,17 +351,36 @@ class EditRealmScreen extends HookConsumerWidget {
|
|||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
CheckboxListTile(
|
Card(
|
||||||
title: const Text('isPublic').tr(),
|
margin: EdgeInsets.zero,
|
||||||
subtitle: const Text('isPublicHint').tr(),
|
child: Column(
|
||||||
value: isPublic.value,
|
children: [
|
||||||
onChanged: (value) => isPublic.value = value ?? false,
|
CheckboxListTile(
|
||||||
),
|
secondary: const Icon(Symbols.public),
|
||||||
CheckboxListTile(
|
title: Text('publicRealm').tr(),
|
||||||
title: const Text('isCommunity').tr(),
|
subtitle: Text('publicRealmDescription').tr(),
|
||||||
subtitle: const Text('isCommunityHint').tr(),
|
value: isPublic.value,
|
||||||
value: isCommunity.value,
|
onChanged: (value) {
|
||||||
onChanged: (value) => isCommunity.value = value ?? false,
|
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),
|
const SizedBox(height: 16),
|
||||||
Align(
|
Align(
|
||||||
@ -435,47 +454,47 @@ class _RealmInviteSheet extends HookConsumerWidget {
|
|||||||
(items) =>
|
(items) =>
|
||||||
items.isEmpty
|
items.isEmpty
|
||||||
? Center(
|
? Center(
|
||||||
child:
|
child:
|
||||||
Text(
|
Text(
|
||||||
'invitesEmpty',
|
'invitesEmpty',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr(),
|
).tr(),
|
||||||
)
|
)
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: items.length,
|
itemCount: items.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final invite = items[index];
|
final invite = items[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: ProfilePictureWidget(
|
leading: ProfilePictureWidget(
|
||||||
fileId: invite.realm!.picture?.id,
|
fileId: invite.realm!.picture?.id,
|
||||||
fallbackIcon: Symbols.group,
|
fallbackIcon: Symbols.group,
|
||||||
),
|
),
|
||||||
title: Text(invite.realm!.name),
|
title: Text(invite.realm!.name),
|
||||||
subtitle:
|
subtitle:
|
||||||
Text(
|
Text(
|
||||||
invite.role >= 100
|
invite.role >= 100
|
||||||
? 'permissionOwner'
|
? 'permissionOwner'
|
||||||
: invite.role >= 50
|
: invite.role >= 50
|
||||||
? 'permissionModerator'
|
? 'permissionModerator'
|
||||||
: 'permissionMember',
|
: 'permissionMember',
|
||||||
).tr(),
|
).tr(),
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.check),
|
icon: const Icon(Symbols.check),
|
||||||
onPressed: () => acceptInvite(invite),
|
onPressed: () => acceptInvite(invite),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.close),
|
icon: const Icon(Symbols.close),
|
||||||
onPressed: () => declineInvite(invite),
|
onPressed: () => declineInvite(invite),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
error:
|
error:
|
||||||
(error, _) => ResponseErrorWidget(
|
(error, _) => ResponseErrorWidget(
|
||||||
@ -485,4 +504,4 @@ class _RealmInviteSheet extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,6 +341,25 @@ class SettingsScreen extends HookConsumerWidget {
|
|||||||
];
|
];
|
||||||
|
|
||||||
final behaviorSettings = [
|
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
|
// Auto translate settings
|
||||||
ListTile(
|
ListTile(
|
||||||
minLeadingWidth: 48,
|
minLeadingWidth: 48,
|
||||||
|
@ -44,7 +44,7 @@ class AudioCallButton extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
await apiClient.post('/chat/realtime/$roomId');
|
await apiClient.post('/chat/realtime/$roomId');
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.push('/chat/call/roomId');
|
context.push('/chat/call/$roomId');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showErrorAlert(e);
|
showErrorAlert(e);
|
||||||
@ -96,7 +96,7 @@ class AudioCallButton extends HookConsumerWidget {
|
|||||||
tooltip: 'Join Ongoing Call',
|
tooltip: 'Join Ongoing Call',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.push('/chat/call/roomId');
|
context.push('/chat/$roomId/call');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -125,6 +125,7 @@ class CloudFileList extends HookConsumerWidget {
|
|||||||
if (!disableZoomIn) {
|
if (!disableZoomIn) {
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
CloudFileZoomIn(item: files[i], heroTag: heroTags[i]),
|
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:image_picker/image_picker.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
|
import 'package:island/models/publisher.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/services/file.dart';
|
import 'package:island/services/file.dart';
|
||||||
|
@ -362,6 +362,7 @@ class PostItem extends HookConsumerWidget {
|
|||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
|
useRootNavigator: true,
|
||||||
builder: (context) => PostRepliesSheet(post: item),
|
builder: (context) => PostRepliesSheet(post: item),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
|
import 'package:island/models/publisher.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/screens/creators/publishers.dart';
|
import 'package:island/screens/creators/publishers.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
|
|
||||||
class PublisherCard extends ConsumerWidget {
|
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/link_preview.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
|
||||||
import 'package:island/services/file.dart';
|
import 'package:island/services/file.dart';
|
||||||
import 'package:mime/mime.dart';
|
import 'package:mime/mime.dart';
|
||||||
|
|
||||||
@ -193,7 +192,6 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
|
|||||||
setState(() => _isLoading = true);
|
setState(() => _isLoading = true);
|
||||||
try {
|
try {
|
||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
final userInfo = ref.read(userInfoProvider.notifier);
|
|
||||||
final serverUrl = ref.read(serverUrlProvider);
|
final serverUrl = ref.read(serverUrlProvider);
|
||||||
|
|
||||||
String content = _messageController.text.trim();
|
String content = _messageController.text.trim();
|
||||||
@ -218,7 +216,7 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
|
|||||||
case ShareContentType.file:
|
case ShareContentType.file:
|
||||||
// Upload files to cloud storage
|
// Upload files to cloud storage
|
||||||
if (widget.content.files?.isNotEmpty == true) {
|
if (widget.content.files?.isNotEmpty == true) {
|
||||||
final token = await userInfo.getAccessToken();
|
final token = ref.watch(tokenProvider)?.token;
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
throw Exception('Authentication required');
|
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
|
# 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
|
# 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.
|
# 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:
|
environment:
|
||||||
sdk: ^3.7.2
|
sdk: ^3.7.2
|
||||||
@ -123,7 +123,7 @@ dependencies:
|
|||||||
receive_sharing_intent: ^1.8.1
|
receive_sharing_intent: ^1.8.1
|
||||||
top_snackbar_flutter: ^3.3.0
|
top_snackbar_flutter: ^3.3.0
|
||||||
textfield_tags:
|
textfield_tags:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/lionelmennig/textfield_tags.git
|
url: https://github.com/lionelmennig/textfield_tags.git
|
||||||
ref: fixes/allow-controller-re-registration
|
ref: fixes/allow-controller-re-registration
|
||||||
mime: ^2.0.0
|
mime: ^2.0.0
|
||||||
|
Reference in New Issue
Block a user