Compare commits
125 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
b66640c6df
|
|||
|
4ac10706ae
|
|||
|
bf2844162d
|
|||
|
23c11a2fbd
|
|||
|
2b99f54bc5
|
|||
|
ab2fc1013b
|
|||
|
|
9a41ff26ef | ||
|
63a55658ab
|
|||
|
|
3122ae4cc2 | ||
|
00e063e99f
|
|||
|
532bb30c6a
|
|||
|
d8c33b576f
|
|||
|
a984cba2fa
|
|||
|
b7d5aa5dfb
|
|||
|
826238a374
|
|||
|
88c4d648d5
|
|||
|
bf59108569
|
|||
|
eec181da55
|
|||
|
c93b543da9
|
|||
|
2fd93246c7
|
|||
|
1b2620e957
|
|||
|
d443343052
|
|||
|
9957905212
|
|||
|
e36d694397
|
|||
|
3847581f1f
|
|||
|
64903bf1f3
|
|||
|
a449fbb58a
|
|||
|
6a4a50b81a
|
|||
|
5e328b736f
|
|||
|
d44e481a0d
|
|||
|
e6fb38572c
|
|||
|
64c5ee0fe9
|
|||
|
9cba568e47
|
|||
|
38fc4e969f
|
|||
|
0e100c3e64
|
|||
|
735724ae4d
|
|||
|
6c31337fbc
|
|||
|
d2806fdc3a
|
|||
|
4ebbda1b14
|
|||
|
3e7007f58f
|
|||
|
d96629a7f1
|
|||
|
1b6ccccf32
|
|||
|
910dafaa43
|
|||
|
c6fd342072
|
|||
|
757f1b880c
|
|||
|
67805b413e
|
|||
|
e1eb0f705e
|
|||
|
1e8e785e5f
|
|||
|
d9dfea6b8b
|
|||
|
d29f0b1170
|
|||
|
479a79c7f6
|
|||
|
1a74f2b3e9
|
|||
|
97a5e951e1
|
|||
|
9071ac44fe
|
|||
|
6abee8d8bd
|
|||
|
8cf03683dc
|
|||
|
f34d80b7d4
|
|||
|
b6d7e52148
|
|||
|
978b7b32fd
|
|||
|
35a9c9ff4b
|
|||
|
e5cb296367
|
|||
|
cf3a2b6340
|
|||
|
f568baf14d
|
|||
|
703335429a
|
|||
|
188b6821a2
|
|||
|
0ebbe0bd5a
|
|||
|
46a826ff86
|
|||
|
1d99ac6441
|
|||
|
e2efdc4064
|
|||
|
cba1a3884b
|
|||
|
7147ce1efa
|
|||
|
78c1a284a5
|
|||
|
f1f5113b01
|
|||
|
a44552f105
|
|||
|
8c1ad94555
|
|||
|
84f5677260
|
|||
|
aa1ffdbf10
|
|||
|
c24d13461b
|
|||
|
3b60fcb87c
|
|||
|
3605b997b1
|
|||
|
800815c721
|
|||
|
3b13a63e7b
|
|||
|
81d69ce10f
|
|||
|
c16d8a5912
|
|||
|
cb9eca0424
|
|||
|
d7858bab67
|
|||
|
5ce590029b
|
|||
|
4d92dec45c
|
|||
|
0a4e797eec
|
|||
|
38dffa414f
|
|||
|
eea56a742e
|
|||
|
56b7ee1d69
|
|||
|
3b564f7e7f
|
|||
|
93d2670063
|
|||
|
788165ac5b
|
|||
|
ec71125fa9
|
|||
|
adb231278c
|
|||
|
b3ae4ab36f
|
|||
|
3670fe0f10
|
|||
|
bb1a5155ed
|
|||
|
eb90dbbc5a
|
|||
|
a73d9f8ec0
|
|||
|
4c8f2e3251
|
|||
|
bc9d2ab8ce
|
|||
|
8bc01f1b97
|
|||
|
200cf3ec80
|
|||
|
d910d837eb
|
|||
|
56d1f14206
|
|||
|
a7c8a8d2ee
|
|||
|
411c71dae0
|
|||
|
a8430604f9
|
|||
|
fe37d219b7
|
|||
|
bc1ebc799a
|
|||
|
37940ef12a
|
|||
|
5d0469e187
|
|||
|
7ad7ab53a6
|
|||
|
6b0343d3dc
|
|||
|
f541580281
|
|||
|
6e7eedc026
|
|||
|
5d5bda7925
|
|||
|
48e66580c3
|
|||
|
836449e3f4
|
|||
|
804dd029b1
|
|||
|
e13928b03f
|
|||
|
5c14236603
|
@@ -17,6 +17,7 @@
|
|||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="Solian"
|
android:label="Solian"
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ 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.plugin.common.MethodChannel
|
||||||
import io.flutter.plugins.sharedpreferences.LegacySharedPreferencesPlugin
|
import io.flutter.plugins.sharedpreferences.LegacySharedPreferencesPlugin
|
||||||
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
|
|
||||||
class MainActivity : FlutterActivity()
|
class MainActivity : FlutterFragmentActivity()
|
||||||
{
|
{
|
||||||
private val CHANNEL = "dev.solsynth.solian/notifications"
|
private val CHANNEL = "dev.solsynth.solian/notifications"
|
||||||
|
|
||||||
|
|||||||
BIN
assets/audio/messages.mp3
Normal file
BIN
assets/audio/messages.mp3
Normal file
Binary file not shown.
BIN
assets/audio/notification.mp3
Normal file
BIN
assets/audio/notification.mp3
Normal file
Binary file not shown.
@@ -23,8 +23,6 @@
|
|||||||
"next": "Next",
|
"next": "Next",
|
||||||
"createAccount": "Create an Account",
|
"createAccount": "Create an Account",
|
||||||
"createAccountDescription": "New to here? We got you covered!",
|
"createAccountDescription": "New to here? We got you covered!",
|
||||||
"affiliationSpell": "Affiliation Spell",
|
|
||||||
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
|
||||||
"nickname": "Nickname",
|
"nickname": "Nickname",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"bio": "Bio",
|
"bio": "Bio",
|
||||||
@@ -32,7 +30,6 @@
|
|||||||
"fieldEmailAddressMustBeValid": "The email address must be valid.",
|
"fieldEmailAddressMustBeValid": "The email address must be valid.",
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"updateYourProfile": "Profile Settings",
|
"updateYourProfile": "Profile Settings",
|
||||||
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
|
||||||
"accountBasicInfo": "Basic Info",
|
"accountBasicInfo": "Basic Info",
|
||||||
"accountProfile": "Your Profile",
|
"accountProfile": "Your Profile",
|
||||||
"saveChanges": "Save Changes",
|
"saveChanges": "Save Changes",
|
||||||
@@ -70,18 +67,15 @@
|
|||||||
"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",
|
"realms": "Realms",
|
||||||
"realmsDescription": "Manage realms you've joined.",
|
|
||||||
"createRealm": "Create a Realm",
|
"createRealm": "Create a Realm",
|
||||||
"createRealmHint": "Meet friends with same interests, build communities, and more.",
|
"createRealmHint": "Meet friends with same interests, build communities, and more.",
|
||||||
"editRealm": "Edit Realm",
|
"editRealm": "Edit Realm",
|
||||||
"deleteRealm": "Delete 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.",
|
"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",
|
||||||
"exploreDescription": "Explore contents on the Solar Network.",
|
|
||||||
"exploreFilterSubscriptions": "Subscriptions",
|
"exploreFilterSubscriptions": "Subscriptions",
|
||||||
"exploreFilterFriends": "Friends",
|
"exploreFilterFriends": "Friends",
|
||||||
"account": "Account",
|
"account": "Account",
|
||||||
"accountDescription": "Information about your 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.",
|
||||||
@@ -90,7 +84,6 @@
|
|||||||
"deleteChatRoom": "Delete Room",
|
"deleteChatRoom": "Delete Room",
|
||||||
"deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.",
|
"deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.",
|
||||||
"chat": "Chat",
|
"chat": "Chat",
|
||||||
"chatDescription": "Group Chats and Direct Messages",
|
|
||||||
"chatTabAll": "All",
|
"chatTabAll": "All",
|
||||||
"chatTabDirect": "Direct Messages",
|
"chatTabDirect": "Direct Messages",
|
||||||
"chatTabGroup": "Group Chats",
|
"chatTabGroup": "Group Chats",
|
||||||
@@ -143,7 +136,6 @@
|
|||||||
"connectionConnected": "Connected",
|
"connectionConnected": "Connected",
|
||||||
"connectionDisconnected": "Disconnected",
|
"connectionDisconnected": "Disconnected",
|
||||||
"connectionReconnecting": "Reconnecting",
|
"connectionReconnecting": "Reconnecting",
|
||||||
"connectionServerDown": "Unable to Connect",
|
|
||||||
"accountConnections": "Account Connections",
|
"accountConnections": "Account Connections",
|
||||||
"accountConnectionsDescription": "Manage your external account connections",
|
"accountConnectionsDescription": "Manage your external account connections",
|
||||||
"accountConnectionAdd": "Add Connection",
|
"accountConnectionAdd": "Add Connection",
|
||||||
@@ -166,7 +158,7 @@
|
|||||||
"checkIn": "Check In",
|
"checkIn": "Check In",
|
||||||
"checkInNone": "Not checked-in yet",
|
"checkInNone": "Not checked-in yet",
|
||||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||||
"checkInResultLevel0": "Wrost Luck",
|
"checkInResultLevel0": "Worst Luck",
|
||||||
"checkInResultLevel1": "Bad Luck",
|
"checkInResultLevel1": "Bad Luck",
|
||||||
"checkInResultLevel2": "A Normal Day",
|
"checkInResultLevel2": "A Normal Day",
|
||||||
"checkInResultLevel3": "Good Luck",
|
"checkInResultLevel3": "Good Luck",
|
||||||
@@ -198,9 +190,7 @@
|
|||||||
"statusActivityTitle": "{} is {} {}",
|
"statusActivityTitle": "{} is {} {}",
|
||||||
"statusActivityEndedTitle": "{} is {} {} until {}",
|
"statusActivityEndedTitle": "{} is {} {} until {}",
|
||||||
"appSettings": "App Settings",
|
"appSettings": "App Settings",
|
||||||
"appSettingsDescription": "Customize your app.",
|
|
||||||
"accountSettings": "Account Settings",
|
"accountSettings": "Account Settings",
|
||||||
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"accountLanguageHint": "This language will be used for email and push notifications.",
|
"accountLanguageHint": "This language will be used for email and push notifications.",
|
||||||
@@ -259,15 +249,31 @@
|
|||||||
"translatorBadgeName": "Translator",
|
"translatorBadgeName": "Translator",
|
||||||
"translatorBadgeDescription": "Helping translate Solar Network into different languages",
|
"translatorBadgeDescription": "Helping translate Solar Network into different languages",
|
||||||
"wallet": "Wallet",
|
"wallet": "Wallet",
|
||||||
"walletDescription": "Your source point wallet.",
|
|
||||||
"walletCurrencyPoints": "New Solar Points",
|
"walletCurrencyPoints": "New Solar Points",
|
||||||
"walletCurrencyShortPoints": "NSP",
|
"walletCurrencyShortPoints": "NSP",
|
||||||
"walletCurrencyGolds": "The Solar Dollars",
|
"walletCurrencyGolds": "The Solar Dollars",
|
||||||
"walletCurrencyShortGolds": "NSD",
|
"walletCurrencyShortGolds": "NSD",
|
||||||
"retry": "Retry",
|
"retry": "Retry",
|
||||||
"creatorHubUnselectedHint": "Pick / create a publisher to get started.",
|
"creatorHubUnselectedHint": "Pick / create a publisher to get started.",
|
||||||
|
"publisherFediverse": "Fediverse Actor",
|
||||||
|
"publisherFediverseDescription": "Configure your publisher's ActivityPub actor for federated social networking",
|
||||||
|
"publisherFediverseEnabled": "Enabled",
|
||||||
|
"publisherFediverseDisabled": "Disabled",
|
||||||
|
"publisherFediverseNotConfigured": "Not configured",
|
||||||
|
"publisherFediverseEnableHint": "Enable your publisher to interact with fediverse",
|
||||||
|
"publisherFediverseDisableHint": "Disable your publisher's fediverse actor",
|
||||||
|
"publisherFediverseEnableConfirm": "Enable fediverse actor?",
|
||||||
|
"publisherFediverseDisableConfirm": "Disable fediverse actor?",
|
||||||
|
"publisherFediverseEnabledSuccess": "Fediverse actor enabled successfully",
|
||||||
|
"publisherFediverseDisabledSuccess": "Fediverse actor disabled successfully",
|
||||||
|
"publisherFediverseFailedToEnable": "Failed to enable fediverse actor",
|
||||||
|
"publisherFediverseFailedToDisable": "Failed to disable fediverse actor",
|
||||||
|
"publisherFediverseWhatIs": "What is Fediverse?",
|
||||||
|
"publisherFediverseAbout": "The fediverse is a federated network of social platforms. Enabling this feature allows your publisher to interact with users across different ActivityPub-compatible services like Mastodon, PeerTube, and more.",
|
||||||
|
"publisherFediverseActorUri": "Actor URI",
|
||||||
|
"publisherFediverseFollowerCount": "Followers",
|
||||||
|
"publisherFediverseNoFollowers": "No followers yet",
|
||||||
"relationships": "Relationships",
|
"relationships": "Relationships",
|
||||||
"relationshipsDescription": "Friends and connections.",
|
|
||||||
"addFriend": "Send a Friend Request",
|
"addFriend": "Send a Friend Request",
|
||||||
"addFriendShort": "Add as Friend",
|
"addFriendShort": "Add as Friend",
|
||||||
"addFriendHint": "Add a friend to your relationship list.",
|
"addFriendHint": "Add a friend to your relationship list.",
|
||||||
@@ -277,14 +283,17 @@
|
|||||||
"relationshipStatusBlocked": "Blocked",
|
"relationshipStatusBlocked": "Blocked",
|
||||||
"blockUser": "Block User",
|
"blockUser": "Block User",
|
||||||
"unblockUser": "Unblock User",
|
"unblockUser": "Unblock User",
|
||||||
|
"forgotRelationship": "Forgot Relationship",
|
||||||
|
"forgotRelationshipConfirm": "Are you sure you want to forget your relationship with {}? This only changes your relationship status with she / her, she / her might not able to see your friend only posts and use other friend only features. But they can send the friend request again.",
|
||||||
|
"relationshipDeleted": "Relationship deleted",
|
||||||
"friendRequestAccepted": "Accepted friend request from {}",
|
"friendRequestAccepted": "Accepted friend request from {}",
|
||||||
"friendRequestDeclined": "Declined friend request from {}",
|
"friendRequestDeclined": "Declined friend request from {}",
|
||||||
"requestExpiredIn": "Expired in {}",
|
"requestExpiredIn": "Expired in {}",
|
||||||
"friendSentRequest": "Sent Friend Requests",
|
"friendRequests": "Friend Requests",
|
||||||
"friendSentRequestEmpty": "No sent friend requests",
|
"friendRequestsEmpty": "No related friend requests",
|
||||||
"friendSentRequestHint": {
|
"friendRequestsHint": {
|
||||||
"one": "{} friend request sent",
|
"one": "{} friend request",
|
||||||
"other": "{} friend requests sent"
|
"other": "{} friend requests"
|
||||||
},
|
},
|
||||||
"levelingProgress": "Leveling Progress",
|
"levelingProgress": "Leveling Progress",
|
||||||
"levelingProgressExperience": "{} EXP",
|
"levelingProgressExperience": "{} EXP",
|
||||||
@@ -311,7 +320,6 @@
|
|||||||
"settingsServerUrl": "Server URL",
|
"settingsServerUrl": "Server URL",
|
||||||
"settingsApplied": "The settings has been applied.",
|
"settingsApplied": "The settings has been applied.",
|
||||||
"notifications": "Notifications",
|
"notifications": "Notifications",
|
||||||
"notificationsDescription": "See what's happended related to you recently.",
|
|
||||||
"posts": "Posts",
|
"posts": "Posts",
|
||||||
"settingsBackgroundImage": "Background Image",
|
"settingsBackgroundImage": "Background Image",
|
||||||
"settingsBackgroundImageClear": "Clear Background Image",
|
"settingsBackgroundImageClear": "Clear Background Image",
|
||||||
@@ -327,7 +335,6 @@
|
|||||||
"settingsAutoTranslate": "Auto Translate",
|
"settingsAutoTranslate": "Auto Translate",
|
||||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||||
"settingsSoundEffects": "Sound Effects",
|
"settingsSoundEffects": "Sound Effects",
|
||||||
"settingsFestivalFeatures": "Festival Limited Features",
|
|
||||||
"settingsEnterToSend": "Enter to Send",
|
"settingsEnterToSend": "Enter to Send",
|
||||||
"settingsTransparentAppBar": "Transparent App Bar",
|
"settingsTransparentAppBar": "Transparent App Bar",
|
||||||
"settingsCustomFonts": "Custom Fonts",
|
"settingsCustomFonts": "Custom Fonts",
|
||||||
@@ -354,7 +361,7 @@
|
|||||||
"accountSettingsHelp": "Account Settings Help",
|
"accountSettingsHelp": "Account Settings Help",
|
||||||
"accountSettingsHelpContent": "This page allows you to manage your account security, privacy, and other settings. If you need assistance, please contact support.",
|
"accountSettingsHelpContent": "This page allows you to manage your account security, privacy, and other settings. If you need assistance, please contact support.",
|
||||||
"unauthorized": "Unauthorized",
|
"unauthorized": "Unauthorized",
|
||||||
"unauthorizedHint": "You're not signed in or session expired, please sign in again.",
|
"unauthorizedHint": "You're not signed in or session expired, please sign in and try again.",
|
||||||
"publisherBelongsTo": "Belongs to {}",
|
"publisherBelongsTo": "Belongs to {}",
|
||||||
"postContent": "Content",
|
"postContent": "Content",
|
||||||
"postSettings": "Settings",
|
"postSettings": "Settings",
|
||||||
@@ -629,7 +636,6 @@
|
|||||||
"tagsHint": "Enter tags, separated by commas",
|
"tagsHint": "Enter tags, separated by commas",
|
||||||
"categories": "Categories",
|
"categories": "Categories",
|
||||||
"categoriesHint": "Enter categories, separated by commas",
|
"categoriesHint": "Enter categories, separated by commas",
|
||||||
"categoriesAndTags": "Categories & Tags",
|
|
||||||
"chatNotJoined": "You have not joined this chat yet.",
|
"chatNotJoined": "You have not joined this chat yet.",
|
||||||
"chatUnableJoin": "You can't join this chat due to it's access control settings.",
|
"chatUnableJoin": "You can't join this chat due to it's access control settings.",
|
||||||
"chatJoin": "Join the Chat",
|
"chatJoin": "Join the Chat",
|
||||||
@@ -681,9 +687,7 @@
|
|||||||
"publisherFeatureDevelopHint": "Currently, this feature is under active development, you need send a request to unlock this feature.",
|
"publisherFeatureDevelopHint": "Currently, this feature is under active development, you need send a request to unlock this feature.",
|
||||||
"learnMore": "Learn More",
|
"learnMore": "Learn More",
|
||||||
"webArticlesStand": "Article Stand",
|
"webArticlesStand": "Article Stand",
|
||||||
"webArticlesStandDescription": "Explore external sites articles.",
|
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"aboutDescription": "Learn more about the Solar Network.",
|
|
||||||
"somethingWentWrong": "Something went wrong",
|
"somethingWentWrong": "Something went wrong",
|
||||||
"editedAt": "Edited at {}",
|
"editedAt": "Edited at {}",
|
||||||
"addAudio": "Add audio",
|
"addAudio": "Add audio",
|
||||||
@@ -704,7 +708,6 @@
|
|||||||
"sharePostPhoto": "Share Post as Photo",
|
"sharePostPhoto": "Share Post as Photo",
|
||||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||||
"abuseReports": "Abuse Reports",
|
"abuseReports": "Abuse Reports",
|
||||||
"abuseReportsDescription": "View and manage abuse reports.",
|
|
||||||
"membershipCancel": "Cancel Membership",
|
"membershipCancel": "Cancel Membership",
|
||||||
"membershipCancelConfirm": "Are you sure to cancel your membership?",
|
"membershipCancelConfirm": "Are you sure to cancel your membership?",
|
||||||
"membershipCancelHint": "Are you sure to cancel your membership? You will not be charged again. Your membership will remain active until the end of the current billing period. And you will not able to resubscribe until the end of the current subscription ends.",
|
"membershipCancelHint": "Are you sure to cancel your membership? You will not be charged again. Your membership will remain active until the end of the current billing period. And you will not able to resubscribe until the end of the current subscription ends.",
|
||||||
@@ -776,7 +779,6 @@
|
|||||||
"publisherCannotBeEmpty": "Publisher cannot be empty",
|
"publisherCannotBeEmpty": "Publisher cannot be empty",
|
||||||
"operationFailed": "Operation failed: {}",
|
"operationFailed": "Operation failed: {}",
|
||||||
"stickerMarketplace": "Sticker Marketplace",
|
"stickerMarketplace": "Sticker Marketplace",
|
||||||
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
|
||||||
"stickerPackAdded": "Sticker pack added to your collection",
|
"stickerPackAdded": "Sticker pack added to your collection",
|
||||||
"stickerPackRemoved": "Sticker pack removed from your collection",
|
"stickerPackRemoved": "Sticker pack removed from your collection",
|
||||||
"addPack": "Add Pack",
|
"addPack": "Add Pack",
|
||||||
@@ -804,7 +806,6 @@
|
|||||||
"joinedAt": "Joined at {}",
|
"joinedAt": "Joined at {}",
|
||||||
"searchAccounts": "Search accounts...",
|
"searchAccounts": "Search accounts...",
|
||||||
"webFeeds": "Web Feeds",
|
"webFeeds": "Web Feeds",
|
||||||
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
|
||||||
"polls": "Polls",
|
"polls": "Polls",
|
||||||
"sharePostSlogan": "Explore more on the Solar Network",
|
"sharePostSlogan": "Explore more on the Solar Network",
|
||||||
"filesListAdditional": {
|
"filesListAdditional": {
|
||||||
@@ -883,7 +884,6 @@
|
|||||||
"contactMethodPublic": "Public",
|
"contactMethodPublic": "Public",
|
||||||
"contactMethodPrivate": "Private",
|
"contactMethodPrivate": "Private",
|
||||||
"discoverRealms": "Realms",
|
"discoverRealms": "Realms",
|
||||||
"discoverRealmsDescription": "Discover new realms and join them.",
|
|
||||||
"discoverPublishers": "Publishers",
|
"discoverPublishers": "Publishers",
|
||||||
"discoverShuffledPost": "Random Posts",
|
"discoverShuffledPost": "Random Posts",
|
||||||
"projects": "Projects",
|
"projects": "Projects",
|
||||||
@@ -927,9 +927,8 @@
|
|||||||
"fileHash": "File Hash",
|
"fileHash": "File Hash",
|
||||||
"exifData": "EXIF Data",
|
"exifData": "EXIF Data",
|
||||||
"postShuffle": "Shuffle Posts",
|
"postShuffle": "Shuffle Posts",
|
||||||
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
"swipeToExplore": "Swipe to explore",
|
||||||
"leveling": "Leveling",
|
"leveling": "Leveling",
|
||||||
"levelingDescription": "See your leveling progress and history.",
|
|
||||||
"levelingHistory": "Leveling History",
|
"levelingHistory": "Leveling History",
|
||||||
"stellarProgram": "Stellar Program",
|
"stellarProgram": "Stellar Program",
|
||||||
"socialCredits": "Social Credits",
|
"socialCredits": "Social Credits",
|
||||||
@@ -1021,7 +1020,6 @@
|
|||||||
"noResultsFound": "No results found",
|
"noResultsFound": "No results found",
|
||||||
"toggleFilters": "Toggle filters",
|
"toggleFilters": "Toggle filters",
|
||||||
"notableDayNext": "{} is in",
|
"notableDayNext": "{} is in",
|
||||||
"notableDayToday": "{} is today!",
|
|
||||||
"expandPoll": "Expand Poll",
|
"expandPoll": "Expand Poll",
|
||||||
"collapsePoll": "Collapse Poll",
|
"collapsePoll": "Collapse Poll",
|
||||||
"embedView": "Embed View",
|
"embedView": "Embed View",
|
||||||
@@ -1041,8 +1039,6 @@
|
|||||||
"uploadFile": "Upload File",
|
"uploadFile": "Upload File",
|
||||||
"authDeviceChallenges": "Device Usage",
|
"authDeviceChallenges": "Device Usage",
|
||||||
"authDeviceHint": "Swipe left to edit label, swipe right to logout device.",
|
"authDeviceHint": "Swipe left to edit label, swipe right to logout device.",
|
||||||
"authSessionLogout": "Logout Session",
|
|
||||||
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
|
||||||
"settingsMessageDisplayStyle": "Message Display Style",
|
"settingsMessageDisplayStyle": "Message Display Style",
|
||||||
"auto": "Auto",
|
"auto": "Auto",
|
||||||
"manual": "Manual",
|
"manual": "Manual",
|
||||||
@@ -1073,7 +1069,6 @@
|
|||||||
"fileSizeExceeded": "File size exceeds the maximum limit of {}",
|
"fileSizeExceeded": "File size exceeds the maximum limit of {}",
|
||||||
"fileTypeNotAccepted": "File type is not accepted by this pool",
|
"fileTypeNotAccepted": "File type is not accepted by this pool",
|
||||||
"files": "Files",
|
"files": "Files",
|
||||||
"filesDescription": "Manage your files on the Solar Network Drive.",
|
|
||||||
"confirmDeleteFile": "Are you sure you want to delete this file?",
|
"confirmDeleteFile": "Are you sure you want to delete this file?",
|
||||||
"deleteFile": "Delete File",
|
"deleteFile": "Delete File",
|
||||||
"failedToDeleteFile": "Failed to delete file",
|
"failedToDeleteFile": "Failed to delete file",
|
||||||
@@ -1138,7 +1133,6 @@
|
|||||||
"installUpdate": "Install update",
|
"installUpdate": "Install update",
|
||||||
"openReleasePage": "Open release page",
|
"openReleasePage": "Open release page",
|
||||||
"postCompose": "Compose Post",
|
"postCompose": "Compose Post",
|
||||||
"postComposeDescription": "Compose a new post",
|
|
||||||
"postPublish": "Publish Post",
|
"postPublish": "Publish Post",
|
||||||
"restoreDraftTitle": "Restore Draft",
|
"restoreDraftTitle": "Restore Draft",
|
||||||
"restoreDraftMessage": "A draft was found. Do you want to restore it?",
|
"restoreDraftMessage": "A draft was found. Do you want to restore it?",
|
||||||
@@ -1332,7 +1326,6 @@
|
|||||||
"aiThought": "AI Thought",
|
"aiThought": "AI Thought",
|
||||||
"aiThoughtTitle": "Let sn-chan think",
|
"aiThoughtTitle": "Let sn-chan think",
|
||||||
"postReferenceUnavailable": "Referenced post is unavailable",
|
"postReferenceUnavailable": "Referenced post is unavailable",
|
||||||
"fabLocation": "FAB Location",
|
|
||||||
"activities": "Activities",
|
"activities": "Activities",
|
||||||
"presenceTypeGaming": "Playing",
|
"presenceTypeGaming": "Playing",
|
||||||
"presenceTypeMusic": "Listening to Music",
|
"presenceTypeMusic": "Listening to Music",
|
||||||
@@ -1341,7 +1334,6 @@
|
|||||||
"backToHub": "Back to Hub",
|
"backToHub": "Back to Hub",
|
||||||
"advancedFilters": "Advanced Filters",
|
"advancedFilters": "Advanced Filters",
|
||||||
"searchPosts": "Search Posts",
|
"searchPosts": "Search Posts",
|
||||||
"searchPostsDescription": "Search posts by title, content, or else.",
|
|
||||||
"sortBy": "Sort by",
|
"sortBy": "Sort by",
|
||||||
"fromDate": "From Date",
|
"fromDate": "From Date",
|
||||||
"toDate": "To Date",
|
"toDate": "To Date",
|
||||||
@@ -1503,6 +1495,8 @@
|
|||||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||||
"dropToShare": "Drop to share",
|
"dropToShare": "Drop to share",
|
||||||
|
"affiliationSpell": "Affiliation Spell",
|
||||||
|
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||||
"friendsOnline": "Friends Online",
|
"friendsOnline": "Friends Online",
|
||||||
"createAccountAlmostThere": "Almost There",
|
"createAccountAlmostThere": "Almost There",
|
||||||
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||||
@@ -1512,6 +1506,33 @@
|
|||||||
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||||
"createAccountProfile": "Create your profile",
|
"createAccountProfile": "Create your profile",
|
||||||
"createAccountToS": "Review Terms & Conditions",
|
"createAccountToS": "Review Terms & Conditions",
|
||||||
|
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||||
|
"realmsDescription": "Manage realms you've joined.",
|
||||||
|
"exploreDescription": "Explore contents on the Solar Network.",
|
||||||
|
"accountDescription": "Information about your account.",
|
||||||
|
"chatDescription": "Group Chats and Direct Messages",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
|
"appSettingsDescription": "Customize your app.",
|
||||||
|
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||||
|
"walletDescription": "Your source point wallet.",
|
||||||
|
"relationshipsDescription": "Friends and connections.",
|
||||||
|
"notificationsDescription": "See what's happended related to you recently.",
|
||||||
|
"settingsFestivalFeatures": "Festival Limited Features",
|
||||||
|
"categoriesAndTags": "Categories & Tags",
|
||||||
|
"webArticlesStandDescription": "Explore external sites articles.",
|
||||||
|
"aboutDescription": "Learn more about the Solar Network.",
|
||||||
|
"abuseReportsDescription": "View and manage abuse reports.",
|
||||||
|
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||||
|
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||||
|
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||||
|
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||||
|
"levelingDescription": "See your leveling progress and history.",
|
||||||
|
"notableDayToday": "{} is today!",
|
||||||
|
"authSessionLogout": "Logout Session",
|
||||||
|
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||||
|
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||||
|
"postComposeDescription": "Compose a new post",
|
||||||
|
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||||
"accountActivationAlert": "Activate your account",
|
"accountActivationAlert": "Activate your account",
|
||||||
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||||
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||||
@@ -1542,5 +1563,34 @@
|
|||||||
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||||
"settingsDefaultScreen": "Default Screen",
|
"settingsDefaultScreen": "Default Screen",
|
||||||
"notableDayChristmas": "Christmas",
|
"notableDayChristmas": "Christmas",
|
||||||
"notableDayNewYear": "New Year"
|
"notableDayNewYear": "New Year",
|
||||||
|
"noSubscription": "No subscriptions",
|
||||||
|
"embedLinks": {
|
||||||
|
"one": "{} link",
|
||||||
|
"other": "{} links"
|
||||||
|
},
|
||||||
|
"searchFediverse": "Search Fediverse",
|
||||||
|
"searchFediverseHint": "Search by address, e.g. {}",
|
||||||
|
"searchFediverseEmpty": "Search for users on other ActivityPub instances",
|
||||||
|
"searchFediverseNoResults": "No users found for this search",
|
||||||
|
"fediverseUsers": "Fediverse Users",
|
||||||
|
"following": "Following",
|
||||||
|
"followers": "Followers",
|
||||||
|
"follow": "Follow",
|
||||||
|
"unfollow": "Unfollow",
|
||||||
|
"followedUser": "Followed @{}",
|
||||||
|
"unfollowedUser": "Unfollowed @{}",
|
||||||
|
"followingEmpty": "You're not following anyone yet",
|
||||||
|
"followersEmpty": "No followers yet",
|
||||||
|
"followingEmptyHint": "Start by searching for users or explore other instances",
|
||||||
|
"fediversePost": "Fediverse Post",
|
||||||
|
"fediversePostDescribe": "Post from the Fediverse Network",
|
||||||
|
"settingsShowFediverseContent": "Show Fediverse Content",
|
||||||
|
"universalSearch": "Universal Search",
|
||||||
|
"universalSearchDescription": "Search content across the Solar Network and the fediverse network.",
|
||||||
|
"tasks": "Tasks",
|
||||||
|
"tasksCount": {
|
||||||
|
"one": "{} task",
|
||||||
|
"other": "{} tasks"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@
|
|||||||
"checkIn": "Check In",
|
"checkIn": "Check In",
|
||||||
"checkInNone": "Not checked-in yet",
|
"checkInNone": "Not checked-in yet",
|
||||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||||
"checkInResultLevel0": "Wrost Luck",
|
"checkInResultLevel0": "Worst Luck",
|
||||||
"checkInResultLevel1": "Bad Luck",
|
"checkInResultLevel1": "Bad Luck",
|
||||||
"checkInResultLevel2": "A Normal Day",
|
"checkInResultLevel2": "A Normal Day",
|
||||||
"checkInResultLevel3": "Good Luck",
|
"checkInResultLevel3": "Good Luck",
|
||||||
@@ -265,6 +265,9 @@
|
|||||||
"relationshipStatusBlocked": "Blocked",
|
"relationshipStatusBlocked": "Blocked",
|
||||||
"blockUser": "Block User",
|
"blockUser": "Block User",
|
||||||
"unblockUser": "Unblock User",
|
"unblockUser": "Unblock User",
|
||||||
|
"forgotRelationship": "Olvidar Relación",
|
||||||
|
"forgotRelationshipConfirm": "¿Estás seguro de que quieres olvidar tu relación con {}?",
|
||||||
|
"relationshipDeleted": "Relación eliminada",
|
||||||
"friendRequestAccepted": "Accepted friend request from {}",
|
"friendRequestAccepted": "Accepted friend request from {}",
|
||||||
"friendRequestDeclined": "Declined friend request from {}",
|
"friendRequestDeclined": "Declined friend request from {}",
|
||||||
"requestExpiredIn": "Expired in {}",
|
"requestExpiredIn": "Expired in {}",
|
||||||
@@ -314,7 +317,6 @@
|
|||||||
"settingsAutoTranslate": "Auto Translate",
|
"settingsAutoTranslate": "Auto Translate",
|
||||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||||
"settingsSoundEffects": "Sound Effects",
|
"settingsSoundEffects": "Sound Effects",
|
||||||
"settingsAprilFoolFeatures": "April Fool Features",
|
|
||||||
"settingsEnterToSend": "Enter to Send",
|
"settingsEnterToSend": "Enter to Send",
|
||||||
"settingsTransparentAppBar": "Transparent App Bar",
|
"settingsTransparentAppBar": "Transparent App Bar",
|
||||||
"settingsCustomFonts": "Custom Fonts",
|
"settingsCustomFonts": "Custom Fonts",
|
||||||
@@ -682,9 +684,9 @@
|
|||||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||||
"postVisibility": "Post Visibility",
|
"postVisibility": "Post Visibility",
|
||||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||||
"sharePostPhoto": "Share Post as Photo",
|
"sharePostPhoto": "Share Post as Photo",
|
||||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||||
"abuseReports": "Abuse Reports",
|
"abuseReports": "Abuse Reports",
|
||||||
@@ -705,7 +707,7 @@
|
|||||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||||
"aboutScreenContactUsTitle": "Contact Us",
|
"aboutScreenContactUsTitle": "Contact Us",
|
||||||
"aboutScreenLicenseTitle": "License",
|
"aboutScreenLicenseTitle": "License",
|
||||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
"aboutScreenLicenseContent": "AGPLv3",
|
||||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||||
@@ -1474,5 +1476,74 @@
|
|||||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||||
"dropToShare": "Drop to share"
|
"dropToShare": "Drop to share",
|
||||||
|
"affiliationSpell": "Affiliation Spell",
|
||||||
|
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||||
|
"friendsOnline": "Friends Online",
|
||||||
|
"createAccountAlmostThere": "Almost There",
|
||||||
|
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||||
|
"createAccountNotice": "Things you need to know before you create an account:",
|
||||||
|
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||||
|
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||||
|
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||||
|
"createAccountProfile": "Create your profile",
|
||||||
|
"createAccountToS": "Review Terms & Conditions",
|
||||||
|
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||||
|
"realmsDescription": "Manage realms you've joined.",
|
||||||
|
"exploreDescription": "Explore contents on the Solar Network.",
|
||||||
|
"accountDescription": "Information about your account.",
|
||||||
|
"chatDescription": "Group Chats and Direct Messages",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
|
"appSettingsDescription": "Customize your app.",
|
||||||
|
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||||
|
"walletDescription": "Your source point wallet.",
|
||||||
|
"relationshipsDescription": "Friends and connections.",
|
||||||
|
"notificationsDescription": "See what's happended related to you recently.",
|
||||||
|
"settingsFestivalFeatures": "Festival Limited Features",
|
||||||
|
"categoriesAndTags": "Categories & Tags",
|
||||||
|
"webArticlesStandDescription": "Explore external sites articles.",
|
||||||
|
"aboutDescription": "Learn more about the Solar Network.",
|
||||||
|
"abuseReportsDescription": "View and manage abuse reports.",
|
||||||
|
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||||
|
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||||
|
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||||
|
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||||
|
"levelingDescription": "See your leveling progress and history.",
|
||||||
|
"notableDayToday": "{} is today!",
|
||||||
|
"authSessionLogout": "Logout Session",
|
||||||
|
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||||
|
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||||
|
"postComposeDescription": "Compose a new post",
|
||||||
|
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||||
|
"accountActivationAlert": "Activate your account",
|
||||||
|
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||||
|
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||||
|
"accountActivationResend": "Resend",
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"noFurtherData": "No further data",
|
||||||
|
"searchAnything": "Search Anything...",
|
||||||
|
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||||
|
"mostRecent": "Most Recent",
|
||||||
|
"noNotificationsYet": "No notifications yet",
|
||||||
|
"recentChats": "Recent Chats",
|
||||||
|
"noFeaturedPostsAvailable": "No featured posts available",
|
||||||
|
"searchChatsAndPages": "Search chats and pages...",
|
||||||
|
"dashboard": "Dashboard",
|
||||||
|
"dashboardDescription": "All your data in one place.",
|
||||||
|
"postTagsCategories": "Post Tags and Categories",
|
||||||
|
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||||
|
"debugLogs": "Debug Logs",
|
||||||
|
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||||
|
"pinChatRoom": "Pin Chat Room",
|
||||||
|
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||||
|
"chatRoomPinned": "Chat room pinned successfully.",
|
||||||
|
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||||
|
"pinnedChatRoom": "Pinned Rooms",
|
||||||
|
"settingsGroupedChatList": "Grouped Chat List",
|
||||||
|
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||||
|
"settingsDashSearchEngine": "Search Engine for web",
|
||||||
|
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||||
|
"settingsDefaultScreen": "Default Screen",
|
||||||
|
"notableDayChristmas": "Christmas",
|
||||||
|
"notableDayNewYear": "New Year"
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
"checkIn": "Check In",
|
"checkIn": "Check In",
|
||||||
"checkInNone": "Not checked-in yet",
|
"checkInNone": "Not checked-in yet",
|
||||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||||
"checkInResultLevel0": "Wrost Luck",
|
"checkInResultLevel0": "Worst Luck",
|
||||||
"checkInResultLevel1": "Bad Luck",
|
"checkInResultLevel1": "Bad Luck",
|
||||||
"checkInResultLevel2": "A Normal Day",
|
"checkInResultLevel2": "A Normal Day",
|
||||||
"checkInResultLevel3": "Good Luck",
|
"checkInResultLevel3": "Good Luck",
|
||||||
@@ -265,6 +265,9 @@
|
|||||||
"relationshipStatusBlocked": "Blocked",
|
"relationshipStatusBlocked": "Blocked",
|
||||||
"blockUser": "Block User",
|
"blockUser": "Block User",
|
||||||
"unblockUser": "Unblock User",
|
"unblockUser": "Unblock User",
|
||||||
|
"forgotRelationship": "関係を忘れる",
|
||||||
|
"forgotRelationshipConfirm": "{} との関係を忘れてもよろしいですか?",
|
||||||
|
"relationshipDeleted": "関係が削除されました",
|
||||||
"friendRequestAccepted": "Accepted friend request from {}",
|
"friendRequestAccepted": "Accepted friend request from {}",
|
||||||
"friendRequestDeclined": "Declined friend request from {}",
|
"friendRequestDeclined": "Declined friend request from {}",
|
||||||
"requestExpiredIn": "Expired in {}",
|
"requestExpiredIn": "Expired in {}",
|
||||||
@@ -314,7 +317,6 @@
|
|||||||
"settingsAutoTranslate": "Auto Translate",
|
"settingsAutoTranslate": "Auto Translate",
|
||||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||||
"settingsSoundEffects": "Sound Effects",
|
"settingsSoundEffects": "Sound Effects",
|
||||||
"settingsAprilFoolFeatures": "April Fool Features",
|
|
||||||
"settingsEnterToSend": "Enter to Send",
|
"settingsEnterToSend": "Enter to Send",
|
||||||
"settingsTransparentAppBar": "Transparent App Bar",
|
"settingsTransparentAppBar": "Transparent App Bar",
|
||||||
"settingsCustomFonts": "Custom Fonts",
|
"settingsCustomFonts": "Custom Fonts",
|
||||||
@@ -682,9 +684,9 @@
|
|||||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||||
"postVisibility": "Post Visibility",
|
"postVisibility": "Post Visibility",
|
||||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||||
"sharePostPhoto": "Share Post as Photo",
|
"sharePostPhoto": "Share Post as Photo",
|
||||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||||
"abuseReports": "Abuse Reports",
|
"abuseReports": "Abuse Reports",
|
||||||
@@ -705,7 +707,7 @@
|
|||||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||||
"aboutScreenContactUsTitle": "Contact Us",
|
"aboutScreenContactUsTitle": "Contact Us",
|
||||||
"aboutScreenLicenseTitle": "License",
|
"aboutScreenLicenseTitle": "License",
|
||||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
"aboutScreenLicenseContent": "AGPLv3",
|
||||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||||
@@ -1474,5 +1476,74 @@
|
|||||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||||
"dropToShare": "Drop to share"
|
"dropToShare": "Drop to share",
|
||||||
|
"affiliationSpell": "Affiliation Spell",
|
||||||
|
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||||
|
"friendsOnline": "Friends Online",
|
||||||
|
"createAccountAlmostThere": "Almost There",
|
||||||
|
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||||
|
"createAccountNotice": "Things you need to know before you create an account:",
|
||||||
|
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||||
|
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||||
|
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||||
|
"createAccountProfile": "Create your profile",
|
||||||
|
"createAccountToS": "Review Terms & Conditions",
|
||||||
|
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||||
|
"realmsDescription": "Manage realms you've joined.",
|
||||||
|
"exploreDescription": "Explore contents on the Solar Network.",
|
||||||
|
"accountDescription": "Information about your account.",
|
||||||
|
"chatDescription": "Group Chats and Direct Messages",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
|
"appSettingsDescription": "Customize your app.",
|
||||||
|
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||||
|
"walletDescription": "Your source point wallet.",
|
||||||
|
"relationshipsDescription": "Friends and connections.",
|
||||||
|
"notificationsDescription": "See what's happended related to you recently.",
|
||||||
|
"settingsFestivalFeatures": "Festival Limited Features",
|
||||||
|
"categoriesAndTags": "Categories & Tags",
|
||||||
|
"webArticlesStandDescription": "Explore external sites articles.",
|
||||||
|
"aboutDescription": "Learn more about the Solar Network.",
|
||||||
|
"abuseReportsDescription": "View and manage abuse reports.",
|
||||||
|
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||||
|
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||||
|
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||||
|
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||||
|
"levelingDescription": "See your leveling progress and history.",
|
||||||
|
"notableDayToday": "{} is today!",
|
||||||
|
"authSessionLogout": "Logout Session",
|
||||||
|
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||||
|
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||||
|
"postComposeDescription": "Compose a new post",
|
||||||
|
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||||
|
"accountActivationAlert": "Activate your account",
|
||||||
|
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||||
|
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||||
|
"accountActivationResend": "Resend",
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"noFurtherData": "No further data",
|
||||||
|
"searchAnything": "Search Anything...",
|
||||||
|
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||||
|
"mostRecent": "Most Recent",
|
||||||
|
"noNotificationsYet": "No notifications yet",
|
||||||
|
"recentChats": "Recent Chats",
|
||||||
|
"noFeaturedPostsAvailable": "No featured posts available",
|
||||||
|
"searchChatsAndPages": "Search chats and pages...",
|
||||||
|
"dashboard": "Dashboard",
|
||||||
|
"dashboardDescription": "All your data in one place.",
|
||||||
|
"postTagsCategories": "Post Tags and Categories",
|
||||||
|
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||||
|
"debugLogs": "Debug Logs",
|
||||||
|
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||||
|
"pinChatRoom": "Pin Chat Room",
|
||||||
|
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||||
|
"chatRoomPinned": "Chat room pinned successfully.",
|
||||||
|
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||||
|
"pinnedChatRoom": "Pinned Rooms",
|
||||||
|
"settingsGroupedChatList": "Grouped Chat List",
|
||||||
|
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||||
|
"settingsDashSearchEngine": "Search Engine for web",
|
||||||
|
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||||
|
"settingsDefaultScreen": "Default Screen",
|
||||||
|
"notableDayChristmas": "Christmas",
|
||||||
|
"notableDayNewYear": "New Year"
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
"checkIn": "Check In",
|
"checkIn": "Check In",
|
||||||
"checkInNone": "Not checked-in yet",
|
"checkInNone": "Not checked-in yet",
|
||||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||||
"checkInResultLevel0": "Wrost Luck",
|
"checkInResultLevel0": "Worst Luck",
|
||||||
"checkInResultLevel1": "Bad Luck",
|
"checkInResultLevel1": "Bad Luck",
|
||||||
"checkInResultLevel2": "A Normal Day",
|
"checkInResultLevel2": "A Normal Day",
|
||||||
"checkInResultLevel3": "Good Luck",
|
"checkInResultLevel3": "Good Luck",
|
||||||
@@ -265,6 +265,9 @@
|
|||||||
"relationshipStatusBlocked": "Blocked",
|
"relationshipStatusBlocked": "Blocked",
|
||||||
"blockUser": "Block User",
|
"blockUser": "Block User",
|
||||||
"unblockUser": "Unblock User",
|
"unblockUser": "Unblock User",
|
||||||
|
"forgotRelationship": "관계 잊기",
|
||||||
|
"forgotRelationshipConfirm": "{}와의 관계를 잊으시겠습니까?",
|
||||||
|
"relationshipDeleted": "관계가 삭제되었습니다",
|
||||||
"friendRequestAccepted": "Accepted friend request from {}",
|
"friendRequestAccepted": "Accepted friend request from {}",
|
||||||
"friendRequestDeclined": "Declined friend request from {}",
|
"friendRequestDeclined": "Declined friend request from {}",
|
||||||
"requestExpiredIn": "Expired in {}",
|
"requestExpiredIn": "Expired in {}",
|
||||||
@@ -314,7 +317,6 @@
|
|||||||
"settingsAutoTranslate": "Auto Translate",
|
"settingsAutoTranslate": "Auto Translate",
|
||||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||||
"settingsSoundEffects": "Sound Effects",
|
"settingsSoundEffects": "Sound Effects",
|
||||||
"settingsAprilFoolFeatures": "April Fool Features",
|
|
||||||
"settingsEnterToSend": "Enter to Send",
|
"settingsEnterToSend": "Enter to Send",
|
||||||
"settingsTransparentAppBar": "Transparent App Bar",
|
"settingsTransparentAppBar": "Transparent App Bar",
|
||||||
"settingsCustomFonts": "Custom Fonts",
|
"settingsCustomFonts": "Custom Fonts",
|
||||||
@@ -682,9 +684,9 @@
|
|||||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||||
"postVisibility": "Post Visibility",
|
"postVisibility": "Post Visibility",
|
||||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||||
"sharePostPhoto": "Share Post as Photo",
|
"sharePostPhoto": "Share Post as Photo",
|
||||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||||
"abuseReports": "Abuse Reports",
|
"abuseReports": "Abuse Reports",
|
||||||
@@ -705,7 +707,7 @@
|
|||||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||||
"aboutScreenContactUsTitle": "Contact Us",
|
"aboutScreenContactUsTitle": "Contact Us",
|
||||||
"aboutScreenLicenseTitle": "License",
|
"aboutScreenLicenseTitle": "License",
|
||||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
"aboutScreenLicenseContent": "AGPLv3",
|
||||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||||
@@ -1474,5 +1476,74 @@
|
|||||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||||
"dropToShare": "Drop to share"
|
"dropToShare": "Drop to share",
|
||||||
|
"affiliationSpell": "Affiliation Spell",
|
||||||
|
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||||
|
"friendsOnline": "Friends Online",
|
||||||
|
"createAccountAlmostThere": "Almost There",
|
||||||
|
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||||
|
"createAccountNotice": "Things you need to know before you create an account:",
|
||||||
|
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||||
|
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||||
|
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||||
|
"createAccountProfile": "Create your profile",
|
||||||
|
"createAccountToS": "Review Terms & Conditions",
|
||||||
|
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||||
|
"realmsDescription": "Manage realms you've joined.",
|
||||||
|
"exploreDescription": "Explore contents on the Solar Network.",
|
||||||
|
"accountDescription": "Information about your account.",
|
||||||
|
"chatDescription": "Group Chats and Direct Messages",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
|
"appSettingsDescription": "Customize your app.",
|
||||||
|
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||||
|
"walletDescription": "Your source point wallet.",
|
||||||
|
"relationshipsDescription": "Friends and connections.",
|
||||||
|
"notificationsDescription": "See what's happended related to you recently.",
|
||||||
|
"settingsFestivalFeatures": "Festival Limited Features",
|
||||||
|
"categoriesAndTags": "Categories & Tags",
|
||||||
|
"webArticlesStandDescription": "Explore external sites articles.",
|
||||||
|
"aboutDescription": "Learn more about the Solar Network.",
|
||||||
|
"abuseReportsDescription": "View and manage abuse reports.",
|
||||||
|
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||||
|
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||||
|
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||||
|
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||||
|
"levelingDescription": "See your leveling progress and history.",
|
||||||
|
"notableDayToday": "{} is today!",
|
||||||
|
"authSessionLogout": "Logout Session",
|
||||||
|
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||||
|
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||||
|
"postComposeDescription": "Compose a new post",
|
||||||
|
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||||
|
"accountActivationAlert": "Activate your account",
|
||||||
|
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||||
|
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||||
|
"accountActivationResend": "Resend",
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"noFurtherData": "No further data",
|
||||||
|
"searchAnything": "Search Anything...",
|
||||||
|
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||||
|
"mostRecent": "Most Recent",
|
||||||
|
"noNotificationsYet": "No notifications yet",
|
||||||
|
"recentChats": "Recent Chats",
|
||||||
|
"noFeaturedPostsAvailable": "No featured posts available",
|
||||||
|
"searchChatsAndPages": "Search chats and pages...",
|
||||||
|
"dashboard": "Dashboard",
|
||||||
|
"dashboardDescription": "All your data in one place.",
|
||||||
|
"postTagsCategories": "Post Tags and Categories",
|
||||||
|
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||||
|
"debugLogs": "Debug Logs",
|
||||||
|
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||||
|
"pinChatRoom": "Pin Chat Room",
|
||||||
|
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||||
|
"chatRoomPinned": "Chat room pinned successfully.",
|
||||||
|
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||||
|
"pinnedChatRoom": "Pinned Rooms",
|
||||||
|
"settingsGroupedChatList": "Grouped Chat List",
|
||||||
|
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||||
|
"settingsDashSearchEngine": "Search Engine for web",
|
||||||
|
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||||
|
"settingsDefaultScreen": "Default Screen",
|
||||||
|
"notableDayChristmas": "Christmas",
|
||||||
|
"notableDayNewYear": "New Year"
|
||||||
}
|
}
|
||||||
@@ -64,8 +64,8 @@
|
|||||||
"authFactorTOTPDescription": "由 TOTP 验证器生成的一次性验证码。",
|
"authFactorTOTPDescription": "由 TOTP 验证器生成的一次性验证码。",
|
||||||
"authFactorInAppNotify": "应用内通知",
|
"authFactorInAppNotify": "应用内通知",
|
||||||
"authFactorInAppNotifyDescription": "通过应用内通知发送的一次性验证码。",
|
"authFactorInAppNotifyDescription": "通过应用内通知发送的一次性验证码。",
|
||||||
"authFactorPin": "Pin 码",
|
"authFactorPin": "PIN 码",
|
||||||
"authFactorPinDescription": "它由6位数字组成。它不能用于登录。 当执行一些危险的操作时,系统将要求您输入此 PIN 进行确认。",
|
"authFactorPinDescription": "此 PIN 码由 6 位数字组成,不可用于登录。执行高风险操作时,系统会要求输入此 PIN 码进行确认。",
|
||||||
"realms": "领域",
|
"realms": "领域",
|
||||||
"createRealm": "创建领域",
|
"createRealm": "创建领域",
|
||||||
"createRealmHint": "结识志同道合的朋友、建立社区等等。",
|
"createRealmHint": "结识志同道合的朋友、建立社区等等。",
|
||||||
@@ -265,6 +265,9 @@
|
|||||||
"relationshipStatusBlocked": "已屏蔽",
|
"relationshipStatusBlocked": "已屏蔽",
|
||||||
"blockUser": "屏蔽用户",
|
"blockUser": "屏蔽用户",
|
||||||
"unblockUser": "解除屏蔽用户",
|
"unblockUser": "解除屏蔽用户",
|
||||||
|
"forgotRelationship": "忘记关系",
|
||||||
|
"forgotRelationshipConfirm": "确定要忘记与 {} 的关系吗?这只会改变您对他/她的关系,他可能看到不到您的友限帖,但是您仍然可以看到他/她的。他/她也可以再次提出好友申请。",
|
||||||
|
"relationshipDeleted": "关系已删除",
|
||||||
"friendRequestAccepted": "已接受 {} 的好友请求",
|
"friendRequestAccepted": "已接受 {} 的好友请求",
|
||||||
"friendRequestDeclined": "已拒绝 {} 的好友请求",
|
"friendRequestDeclined": "已拒绝 {} 的好友请求",
|
||||||
"requestExpiredIn": "{} 后过期",
|
"requestExpiredIn": "{} 后过期",
|
||||||
@@ -314,7 +317,6 @@
|
|||||||
"settingsAutoTranslate": "自动翻译",
|
"settingsAutoTranslate": "自动翻译",
|
||||||
"settingsHideBottomNav": "隐藏底部导航",
|
"settingsHideBottomNav": "隐藏底部导航",
|
||||||
"settingsSoundEffects": "音效",
|
"settingsSoundEffects": "音效",
|
||||||
"settingsAprilFoolFeatures": "愚人节功能",
|
|
||||||
"settingsEnterToSend": "按下 Enter 发送",
|
"settingsEnterToSend": "按下 Enter 发送",
|
||||||
"settingsTransparentAppBar": "使用完全透明的状态栏",
|
"settingsTransparentAppBar": "使用完全透明的状态栏",
|
||||||
"settingsCustomFonts": "自定义字体",
|
"settingsCustomFonts": "自定义字体",
|
||||||
@@ -411,7 +413,7 @@
|
|||||||
"contactMethodAddressHint": "输入您的现实地址",
|
"contactMethodAddressHint": "输入您的现实地址",
|
||||||
"contactMethodEmailDescription": "您的电子邮件将用于帐户恢复和通知",
|
"contactMethodEmailDescription": "您的电子邮件将用于帐户恢复和通知",
|
||||||
"contactMethodPhoneDescription": "您的电话号码将用于帐户恢复和通知",
|
"contactMethodPhoneDescription": "您的电话号码将用于帐户恢复和通知",
|
||||||
"contactMethodAddressDescription": "您的实际地址将用于运输和计费目的。",
|
"contactMethodAddressDescription": "您的地址将用于物流和账单。",
|
||||||
"contactMethodVerified": "已验证",
|
"contactMethodVerified": "已验证",
|
||||||
"contactMethodUnverified": "未认证",
|
"contactMethodUnverified": "未认证",
|
||||||
"contactMethodVerify": "验证联系方式",
|
"contactMethodVerify": "验证联系方式",
|
||||||
@@ -456,6 +458,7 @@
|
|||||||
"checkInResultT2": "中平",
|
"checkInResultT2": "中平",
|
||||||
"checkInResultT3": "吉",
|
"checkInResultT3": "吉",
|
||||||
"checkInResultT4": "大吉",
|
"checkInResultT4": "大吉",
|
||||||
|
"checkInResultT5": "特殊",
|
||||||
"accountProfileView": "查看个人资料",
|
"accountProfileView": "查看个人资料",
|
||||||
"unspecified": "未指定",
|
"unspecified": "未指定",
|
||||||
"added": "已添加",
|
"added": "已添加",
|
||||||
@@ -470,7 +473,7 @@
|
|||||||
"pinCode": "PIN 码",
|
"pinCode": "PIN 码",
|
||||||
"biometric": "生物识别",
|
"biometric": "生物识别",
|
||||||
"enterPinToConfirm": "请输入您的 6 位数字 PIN 以确认付款",
|
"enterPinToConfirm": "请输入您的 6 位数字 PIN 以确认付款",
|
||||||
"clearPin": "清除 PIN 码",
|
"clearPin": "清除 PIN",
|
||||||
"useBiometricToConfirm": "使用生物特征认证来确认付款",
|
"useBiometricToConfirm": "使用生物特征认证来确认付款",
|
||||||
"touchSensorToAuthenticate": "触摸传感器进行身份验证",
|
"touchSensorToAuthenticate": "触摸传感器进行身份验证",
|
||||||
"authenticating": "认证中……",
|
"authenticating": "认证中……",
|
||||||
@@ -479,7 +482,7 @@
|
|||||||
"processingPayment": "处理付款中……",
|
"processingPayment": "处理付款中……",
|
||||||
"pleaseWait": "请稍候",
|
"pleaseWait": "请稍候",
|
||||||
"paymentFailed": "付款失败,请重试。",
|
"paymentFailed": "付款失败,请重试。",
|
||||||
"invalidPin": "错误的 PIN。请再试一次。",
|
"invalidPin": "PIN 码错误,请重试。",
|
||||||
"biometricAuthFailed": "生物识别身份验证失败。请重试。",
|
"biometricAuthFailed": "生物识别身份验证失败。请重试。",
|
||||||
"paymentSuccess": "付款成功完成!",
|
"paymentSuccess": "付款成功完成!",
|
||||||
"membershipPurchaseSuccess": "好耶,会员购买成功!",
|
"membershipPurchaseSuccess": "好耶,会员购买成功!",
|
||||||
@@ -523,7 +526,7 @@
|
|||||||
"safetyReportReasonHint": "请提供更多证据……",
|
"safetyReportReasonHint": "请提供更多证据……",
|
||||||
"safetyReportSubmit": "提交举报",
|
"safetyReportSubmit": "提交举报",
|
||||||
"safetyReportSubmitting": "提交中……",
|
"safetyReportSubmitting": "提交中……",
|
||||||
"safetyReportSuccess": "举报成功,感谢您参与维护社区健康发展。",
|
"safetyReportSuccess": "举报提交成功,感谢您协助维护社区安全。",
|
||||||
"safetyReportError": "举报失败,请稍后重试。",
|
"safetyReportError": "举报失败,请稍后重试。",
|
||||||
"safetyReportReasonRequired": "请提供举报证据",
|
"safetyReportReasonRequired": "请提供举报证据",
|
||||||
"safetyReportTypeSpam": "垃圾或导向错误",
|
"safetyReportTypeSpam": "垃圾或导向错误",
|
||||||
@@ -597,7 +600,7 @@
|
|||||||
"abuseReportReason": "补充详情",
|
"abuseReportReason": "补充详情",
|
||||||
"abuseReportReasonHint": "请提供更多详情……",
|
"abuseReportReasonHint": "请提供更多详情……",
|
||||||
"abuseReportSubmit": "提交举报",
|
"abuseReportSubmit": "提交举报",
|
||||||
"abuseReportSuccess": "举报提交成功,感谢你为社区维护作出贡献。",
|
"abuseReportSuccess": "举报提交成功,感谢您协助维护社区安全。",
|
||||||
"abuseReportError": "无法提交举报,请稍后再试。",
|
"abuseReportError": "无法提交举报,请稍后再试。",
|
||||||
"abuseReportReasonRequired": "请提供关于此事件的细节",
|
"abuseReportReasonRequired": "请提供关于此事件的细节",
|
||||||
"abuseReportSuccessTitle": "举报已提交",
|
"abuseReportSuccessTitle": "举报已提交",
|
||||||
@@ -682,9 +685,9 @@
|
|||||||
"articleAttachmentHint": "附件必须上传并插入到文章主体中才能显示出来。",
|
"articleAttachmentHint": "附件必须上传并插入到文章主体中才能显示出来。",
|
||||||
"postVisibility": "可见性",
|
"postVisibility": "可见性",
|
||||||
"currentMembershipMember": "恒星计划成员 · {}",
|
"currentMembershipMember": "恒星计划成员 · {}",
|
||||||
"membershipPriceStellar": "需要用户等级 3+,每月价格 1200 NSP",
|
"membershipPriceStellar": "需要用户等级达到 20 以上,每月价格 1200 NSP",
|
||||||
"membershipPriceNova": "需要用户等级 6+,每月价格 2400 NSP",
|
"membershipPriceNova": "需要用户等级达到 40 以上,每月价格 2400 NSP",
|
||||||
"membershipPriceSupernova": "需要用户等级 9+,每月价格 3600 NSP",
|
"membershipPriceSupernova": "需要用户等级达到 60 以上,每月价格 3600 NSP",
|
||||||
"sharePostPhoto": "通过图片分享帖子",
|
"sharePostPhoto": "通过图片分享帖子",
|
||||||
"wouldYouLikeToNavigateToChat": "你想要前往聊天页面吗?",
|
"wouldYouLikeToNavigateToChat": "你想要前往聊天页面吗?",
|
||||||
"abuseReports": "举报",
|
"abuseReports": "举报",
|
||||||
@@ -705,7 +708,7 @@
|
|||||||
"aboutScreenDeveloperSectionTitle": "开发者",
|
"aboutScreenDeveloperSectionTitle": "开发者",
|
||||||
"aboutScreenContactUsTitle": "联系我们",
|
"aboutScreenContactUsTitle": "联系我们",
|
||||||
"aboutScreenLicenseTitle": "许可",
|
"aboutScreenLicenseTitle": "许可",
|
||||||
"aboutScreenLicenseContent": "AGPLv3",
|
"aboutScreenLicenseContent": "GNU Affero 通用公共许可证 v3.0",
|
||||||
"aboutScreenCopyright": "版权所有 © Solsynth {}",
|
"aboutScreenCopyright": "版权所有 © Solsynth {}",
|
||||||
"aboutScreenMadeWith": "由 Solar Network 团队用 ❤︎️ 制作",
|
"aboutScreenMadeWith": "由 Solar Network 团队用 ❤︎️ 制作",
|
||||||
"aboutScreenFailedToLoadPackageInfo": "无法加载包信息:{error}",
|
"aboutScreenFailedToLoadPackageInfo": "无法加载包信息:{error}",
|
||||||
@@ -935,8 +938,8 @@
|
|||||||
"keyName": "密钥名称",
|
"keyName": "密钥名称",
|
||||||
"newKeyGenerated": "新密钥已生成",
|
"newKeyGenerated": "新密钥已生成",
|
||||||
"copyKeyHint": "请安全的保存该密钥,你不会再次看到它。",
|
"copyKeyHint": "请安全的保存该密钥,你不会再次看到它。",
|
||||||
"rotateKey": "旋转密钥",
|
"rotateKey": "轮换密钥",
|
||||||
"rotateBotKey": "旋转密钥",
|
"rotateBotKey": "轮换机器人密钥",
|
||||||
"rotateBotKeyHint": "你确认要旋转这个密钥?久的密钥会立即失效,该操作无法撤销。",
|
"rotateBotKeyHint": "你确认要旋转这个密钥?久的密钥会立即失效,该操作无法撤销。",
|
||||||
"webFeedArticleCount": {
|
"webFeedArticleCount": {
|
||||||
"zero": "没有文章",
|
"zero": "没有文章",
|
||||||
@@ -999,7 +1002,6 @@
|
|||||||
"noResultsFound": "未找到结果",
|
"noResultsFound": "未找到结果",
|
||||||
"toggleFilters": "切换过滤器",
|
"toggleFilters": "切换过滤器",
|
||||||
"notableDayNext": "距离 {} 还有",
|
"notableDayNext": "距离 {} 还有",
|
||||||
"notableDayToday": "今天是 {}!",
|
|
||||||
"expandPoll": "展开投票",
|
"expandPoll": "展开投票",
|
||||||
"collapsePoll": "折叠投票",
|
"collapsePoll": "折叠投票",
|
||||||
"embedView": "嵌入视图",
|
"embedView": "嵌入视图",
|
||||||
@@ -1270,7 +1272,7 @@
|
|||||||
"cost": "花费",
|
"cost": "花费",
|
||||||
"multiplier": "倍率",
|
"multiplier": "倍率",
|
||||||
"prizeWon": "获奖者",
|
"prizeWon": "获奖者",
|
||||||
"pending": "待开奖",
|
"pending": "准备中",
|
||||||
"drawn": "已开奖",
|
"drawn": "已开奖",
|
||||||
"won": "赢",
|
"won": "赢",
|
||||||
"lost": "输",
|
"lost": "输",
|
||||||
@@ -1477,19 +1479,72 @@
|
|||||||
"lotteryMultiplierRange": "倍率必须在 1 到 10 之间",
|
"lotteryMultiplierRange": "倍率必须在 1 到 10 之间",
|
||||||
"dropToShare": "拖到此处以分享",
|
"dropToShare": "拖到此处以分享",
|
||||||
"affiliationSpell": "邀请码",
|
"affiliationSpell": "邀请码",
|
||||||
"affiliationSpellHint": "如果您有邀请码,请在此处输入。",
|
"affiliationSpellHint": "如果您有邀请码,请在这里输入。",
|
||||||
"friendsOnline": "在线好友",
|
"friendsOnline": "在线好友",
|
||||||
"createAccountAlmostThere": "就差一步",
|
"createAccountAlmostThere": "即将完成",
|
||||||
"createAccountAlmostThereHint": "您距离加入 Solar Network 仅一步之遥!请解决接下来显示的验证码谜题。",
|
"createAccountAlmostThereHint": "您距离加入 Solar Network 只差一步了!请完成接下来显示的人机验证。",
|
||||||
"createAccountNotice": "创建账户前您需要了解的事项:",
|
"createAccountNotice": "在创建账户之前需要了解的事项:",
|
||||||
"createAccountConfirmEmail": "账户创建后,您需要前往您的邮箱收件箱激活账户,以获得使用所有功能的权限。",
|
"createAccountConfirmEmail": "在账户创建后,您需要去邮箱激活您的账户,以获得使用所有功能的权限。",
|
||||||
"createAccountNoAltAccounts": "Solar Network 禁止使用多个或替代账户,这会违反我们的服务条款。",
|
"createAccountNoAltAccounts": "在 Solar Network 上禁止使用多个账户或替代账户,这将违反我们的服务条款。",
|
||||||
"createAccountAgreeTerms": "我已阅读并同意服务条款。",
|
"createAccountAgreeTerms": "我已经阅读并同意这些服务协议。",
|
||||||
"createAccountProfile": "创建您的个人资料",
|
"createAccountProfile": "创建您的个人资料",
|
||||||
"createAccountToS": "查看条款与条件",
|
"createAccountToS": "查看用户协议 & 服务条款",
|
||||||
"accountActivationAlert": "激活您的账户",
|
"updateYourProfileDescription": "在 Solar Network 上完善你的个人形象。",
|
||||||
"accountActivationAlertHint": "未激活的账户可能会导致各种权限问题,请点击我们发送到您邮箱收件箱的链接来激活您的账户。",
|
"realmsDescription": "管理您已加入的领域。",
|
||||||
"accountActivationResendHint": "没收到?请尝试点击下方按钮重新发送。如果您在账户未激活期间需要更新邮箱,请随时联系我们的客服。",
|
"exploreDescription": "探索 Solar Network 上的内容。",
|
||||||
|
"accountDescription": "关于您账户的信息。",
|
||||||
|
"chatDescription": "群组聊天与私聊",
|
||||||
|
"connectionServerDown": "无法连接",
|
||||||
|
"appSettingsDescription": "自定义您的应用程序。",
|
||||||
|
"accountSettingsDescription": "管理您在 Solar Network 上的偏好设置。",
|
||||||
|
"walletDescription": "您的源点钱包。",
|
||||||
|
"relationshipsDescription": "好友与联系人。",
|
||||||
|
"notificationsDescription": "查看最近与您相关的事情。",
|
||||||
|
"settingsFestivalFeatures": "节日限定功能",
|
||||||
|
"categoriesAndTags": "类别 & 标签",
|
||||||
|
"webArticlesStandDescription": "浏览外部网站文章。",
|
||||||
|
"aboutDescription": "了解更多有关 Solar Network 的信息。",
|
||||||
|
"abuseReportsDescription": "查看并管理滥用报告。",
|
||||||
|
"stickerMarketplaceDescription": "浏览并从 Solar Network 市场添加贴纸包。",
|
||||||
|
"webFeedsDescription": "浏览并订阅 Solar Network 的网页订阅源。",
|
||||||
|
"discoverRealmsDescription": "发现领域并加入它们。",
|
||||||
|
"postShuffleDescription": "打乱帖子以随机查看帖子。",
|
||||||
|
"levelingDescription": "查看您的升级进度和历史记录。",
|
||||||
|
"notableDayToday": "{} 就是今天!",
|
||||||
|
"authSessionLogout": "注销登录",
|
||||||
|
"authSessionLogoutHint": "确认要退出登录吗?此操作将仅结束当前浏览会话,不会影响其他已登录的设备。",
|
||||||
|
"filesDescription": "在 Solar Network Drive 管理您的文件。",
|
||||||
|
"postComposeDescription": "撰写一篇新帖子",
|
||||||
|
"searchPostsDescription": "输入标题、正文或关键词进行搜索。",
|
||||||
|
"accountActivationAlert": "激活您的账号",
|
||||||
|
"accountActivationAlertHint": "账户未激活将无法使用完整功能,请查收邮件并点击链接完成激活。",
|
||||||
|
"accountActivationResendHint": "没收到邮件?请点击下方按钮重新发送。若需在账户未激活时更新邮箱,请联系我们的客服。",
|
||||||
"accountActivationResend": "重新发送",
|
"accountActivationResend": "重新发送",
|
||||||
"noFurtherData": "已经到底了"
|
"ipAddress": "IP 地址",
|
||||||
|
"noFurtherData": "没有更多数据",
|
||||||
|
"searchAnything": "搜索任何内容……",
|
||||||
|
"tapToViewAllNotifications": "轻点显示所有通知",
|
||||||
|
"mostRecent": "最近",
|
||||||
|
"noNotificationsYet": "没有通知",
|
||||||
|
"recentChats": "最近聊天",
|
||||||
|
"noFeaturedPostsAvailable": "没有可用的精选文章",
|
||||||
|
"searchChatsAndPages": "搜索聊天或页面……",
|
||||||
|
"dashboard": "仪表板",
|
||||||
|
"dashboardDescription": "在一处整合您的所有数据。",
|
||||||
|
"postTagsCategories": "文章标签和分类",
|
||||||
|
"postTagsCategoriesDescription": "按类别和标签浏览帖子。",
|
||||||
|
"debugLogs": "调试日志",
|
||||||
|
"debugLogsDescription": "查看调试日志以进行故障排除。",
|
||||||
|
"pinChatRoom": "置顶聊天室",
|
||||||
|
"pinChatRoomDescription": "将此聊天室固定到顶部。",
|
||||||
|
"chatRoomPinned": "聊天室已置顶。",
|
||||||
|
"chatRoomUnpinned": "聊天室已取消置顶。",
|
||||||
|
"pinnedChatRoom": "已置顶的聊天室",
|
||||||
|
"settingsGroupedChatList": "启用群组聊天列表分组",
|
||||||
|
"settingsNotifyWithHaptic": "通知触感反馈",
|
||||||
|
"settingsDashSearchEngine": "网络搜索引擎",
|
||||||
|
"settingsDashSearchEngineHelper": "请使用 %s 作为搜索词的占位符。",
|
||||||
|
"settingsDefaultScreen": "默认起始页面",
|
||||||
|
"notableDayChristmas": "圣诞节",
|
||||||
|
"notableDayNewYear": "新年"
|
||||||
}
|
}
|
||||||
@@ -265,6 +265,9 @@
|
|||||||
"relationshipStatusBlocked": "已阻",
|
"relationshipStatusBlocked": "已阻",
|
||||||
"blockUser": "禁此戶",
|
"blockUser": "禁此戶",
|
||||||
"unblockUser": "解禁",
|
"unblockUser": "解禁",
|
||||||
|
"forgotRelationship": "忘締交",
|
||||||
|
"forgotRelationshipConfirm": "確定要忘與 {} 之締交乎?",
|
||||||
|
"relationshipDeleted": "締交已忘",
|
||||||
"friendRequestAccepted": "已納 {} 締交書",
|
"friendRequestAccepted": "已納 {} 締交書",
|
||||||
"friendRequestDeclined": "已謝 {} 締交書",
|
"friendRequestDeclined": "已謝 {} 締交書",
|
||||||
"requestExpiredIn": "效期 {}",
|
"requestExpiredIn": "效期 {}",
|
||||||
@@ -314,7 +317,6 @@
|
|||||||
"settingsAutoTranslate": "自轉譯",
|
"settingsAutoTranslate": "自轉譯",
|
||||||
"settingsHideBottomNav": "隱底航",
|
"settingsHideBottomNav": "隱底航",
|
||||||
"settingsSoundEffects": "音效",
|
"settingsSoundEffects": "音效",
|
||||||
"settingsAprilFoolFeatures": "謔辰妙能",
|
|
||||||
"settingsEnterToSend": "叩回車鍵即送",
|
"settingsEnterToSend": "叩回車鍵即送",
|
||||||
"settingsTransparentAppBar": "透光應用欄",
|
"settingsTransparentAppBar": "透光應用欄",
|
||||||
"settingsCustomFonts": "自定字體",
|
"settingsCustomFonts": "自定字體",
|
||||||
@@ -328,13 +330,13 @@
|
|||||||
"accountDeletion": "除去此账户",
|
"accountDeletion": "除去此账户",
|
||||||
"accountDeletionHint": "汝已存心除此账户?如已一意,信将至汝邮址,随信中之言续此行。",
|
"accountDeletionHint": "汝已存心除此账户?如已一意,信将至汝邮址,随信中之言续此行。",
|
||||||
"accountDeletionSent": "除此账户之信已送至,请于汝之邮址查阅。",
|
"accountDeletionSent": "除此账户之信已送至,请于汝之邮址查阅。",
|
||||||
"accountSecurityTitle": "Security",
|
"accountSecurityTitle": "保护措施",
|
||||||
"accountDangerZoneTitle": "Danger Zone",
|
"accountDangerZoneTitle": "危险地区",
|
||||||
"accountPassword": "密碼",
|
"accountPassword": "密碼",
|
||||||
"accountPasswordDescription": "變更账户密碼",
|
"accountPasswordDescription": "變更账户密碼",
|
||||||
"accountPasswordChange": "變更密碼",
|
"accountPasswordChange": "變更密碼",
|
||||||
"accountPasswordChangeSent": "Password reset link sent, please check your email inbox.",
|
"accountPasswordChangeSent": "密码重置链接已发送,请查看您的电子邮箱收件箱。",
|
||||||
"accountPasswordChangeDescription": "We will send an email to your primary email address to reset your password.",
|
"accountPasswordChangeDescription": "我们将向您的主要电子邮箱发送一封邮件以重置您的密码。",
|
||||||
"accountAuthFactor": "Auth factors",
|
"accountAuthFactor": "Auth factors",
|
||||||
"accountAuthFactorDescription": "Multi-factor authentication to ensure safety and convience",
|
"accountAuthFactorDescription": "Multi-factor authentication to ensure safety and convience",
|
||||||
"accountDeletionDescription": "Permanently delete your account and all your data",
|
"accountDeletionDescription": "Permanently delete your account and all your data",
|
||||||
@@ -456,6 +458,7 @@
|
|||||||
"checkInResultT2": "Mid",
|
"checkInResultT2": "Mid",
|
||||||
"checkInResultT3": "Good",
|
"checkInResultT3": "Good",
|
||||||
"checkInResultT4": "Best",
|
"checkInResultT4": "Best",
|
||||||
|
"checkInResultT5": "Special",
|
||||||
"accountProfileView": "View Profile",
|
"accountProfileView": "View Profile",
|
||||||
"unspecified": "Unspecified",
|
"unspecified": "Unspecified",
|
||||||
"added": "Added",
|
"added": "Added",
|
||||||
@@ -682,9 +685,9 @@
|
|||||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||||
"postVisibility": "Post Visibility",
|
"postVisibility": "Post Visibility",
|
||||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||||
"sharePostPhoto": "Share Post as Photo",
|
"sharePostPhoto": "Share Post as Photo",
|
||||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||||
"abuseReports": "Abuse Reports",
|
"abuseReports": "Abuse Reports",
|
||||||
@@ -705,7 +708,7 @@
|
|||||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||||
"aboutScreenContactUsTitle": "Contact Us",
|
"aboutScreenContactUsTitle": "Contact Us",
|
||||||
"aboutScreenLicenseTitle": "License",
|
"aboutScreenLicenseTitle": "License",
|
||||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
"aboutScreenLicenseContent": "AGPLv3",
|
||||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||||
@@ -1474,5 +1477,74 @@
|
|||||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||||
"dropToShare": "Drop to share"
|
"dropToShare": "Drop to share",
|
||||||
|
"affiliationSpell": "Affiliation Spell",
|
||||||
|
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||||
|
"friendsOnline": "Friends Online",
|
||||||
|
"createAccountAlmostThere": "Almost There",
|
||||||
|
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||||
|
"createAccountNotice": "Things you need to know before you create an account:",
|
||||||
|
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||||
|
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||||
|
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||||
|
"createAccountProfile": "Create your profile",
|
||||||
|
"createAccountToS": "Review Terms & Conditions",
|
||||||
|
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||||
|
"realmsDescription": "Manage realms you've joined.",
|
||||||
|
"exploreDescription": "Explore contents on the Solar Network.",
|
||||||
|
"accountDescription": "Information about your account.",
|
||||||
|
"chatDescription": "Group Chats and Direct Messages",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
|
"appSettingsDescription": "Customize your app.",
|
||||||
|
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||||
|
"walletDescription": "Your source point wallet.",
|
||||||
|
"relationshipsDescription": "Friends and connections.",
|
||||||
|
"notificationsDescription": "See what's happended related to you recently.",
|
||||||
|
"settingsFestivalFeatures": "Festival Limited Features",
|
||||||
|
"categoriesAndTags": "Categories & Tags",
|
||||||
|
"webArticlesStandDescription": "Explore external sites articles.",
|
||||||
|
"aboutDescription": "Learn more about the Solar Network.",
|
||||||
|
"abuseReportsDescription": "View and manage abuse reports.",
|
||||||
|
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||||
|
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||||
|
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||||
|
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||||
|
"levelingDescription": "See your leveling progress and history.",
|
||||||
|
"notableDayToday": "{} is today!",
|
||||||
|
"authSessionLogout": "Logout Session",
|
||||||
|
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||||
|
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||||
|
"postComposeDescription": "Compose a new post",
|
||||||
|
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||||
|
"accountActivationAlert": "Activate your account",
|
||||||
|
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||||
|
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||||
|
"accountActivationResend": "Resend",
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"noFurtherData": "No further data",
|
||||||
|
"searchAnything": "Search Anything...",
|
||||||
|
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||||
|
"mostRecent": "Most Recent",
|
||||||
|
"noNotificationsYet": "No notifications yet",
|
||||||
|
"recentChats": "Recent Chats",
|
||||||
|
"noFeaturedPostsAvailable": "No featured posts available",
|
||||||
|
"searchChatsAndPages": "Search chats and pages...",
|
||||||
|
"dashboard": "Dashboard",
|
||||||
|
"dashboardDescription": "All your data in one place.",
|
||||||
|
"postTagsCategories": "Post Tags and Categories",
|
||||||
|
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||||
|
"debugLogs": "Debug Logs",
|
||||||
|
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||||
|
"pinChatRoom": "Pin Chat Room",
|
||||||
|
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||||
|
"chatRoomPinned": "Chat room pinned successfully.",
|
||||||
|
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||||
|
"pinnedChatRoom": "Pinned Rooms",
|
||||||
|
"settingsGroupedChatList": "Grouped Chat List",
|
||||||
|
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||||
|
"settingsDashSearchEngine": "Search Engine for web",
|
||||||
|
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||||
|
"settingsDefaultScreen": "Default Screen",
|
||||||
|
"notableDayChristmas": "Christmas",
|
||||||
|
"notableDayNewYear": "New Year"
|
||||||
}
|
}
|
||||||
@@ -265,6 +265,9 @@
|
|||||||
"relationshipStatusBlocked": "已屏蔽",
|
"relationshipStatusBlocked": "已屏蔽",
|
||||||
"blockUser": "屏蔽用戶",
|
"blockUser": "屏蔽用戶",
|
||||||
"unblockUser": "解除屏蔽用戶",
|
"unblockUser": "解除屏蔽用戶",
|
||||||
|
"forgotRelationship": "忘記關係",
|
||||||
|
"forgotRelationshipConfirm": "確定要忘記與 {} 的關係嗎?",
|
||||||
|
"relationshipDeleted": "關係已刪除",
|
||||||
"friendRequestAccepted": "已接受 {} 的好友請求",
|
"friendRequestAccepted": "已接受 {} 的好友請求",
|
||||||
"friendRequestDeclined": "已拒絕 {} 的好友請求",
|
"friendRequestDeclined": "已拒絕 {} 的好友請求",
|
||||||
"requestExpiredIn": "{} 後過期",
|
"requestExpiredIn": "{} 後過期",
|
||||||
@@ -314,7 +317,6 @@
|
|||||||
"settingsAutoTranslate": "自動翻譯",
|
"settingsAutoTranslate": "自動翻譯",
|
||||||
"settingsHideBottomNav": "隱藏底部導航",
|
"settingsHideBottomNav": "隱藏底部導航",
|
||||||
"settingsSoundEffects": "音效",
|
"settingsSoundEffects": "音效",
|
||||||
"settingsAprilFoolFeatures": "愚人節功能",
|
|
||||||
"settingsEnterToSend": "按下 Enter 發送",
|
"settingsEnterToSend": "按下 Enter 發送",
|
||||||
"settingsTransparentAppBar": "使用完全透明的狀態欄",
|
"settingsTransparentAppBar": "使用完全透明的狀態欄",
|
||||||
"settingsCustomFonts": "自定義字體",
|
"settingsCustomFonts": "自定義字體",
|
||||||
@@ -456,6 +458,7 @@
|
|||||||
"checkInResultT2": "中平",
|
"checkInResultT2": "中平",
|
||||||
"checkInResultT3": "吉",
|
"checkInResultT3": "吉",
|
||||||
"checkInResultT4": "大吉",
|
"checkInResultT4": "大吉",
|
||||||
|
"checkInResultT5": "特殊",
|
||||||
"accountProfileView": "查看個人資料",
|
"accountProfileView": "查看個人資料",
|
||||||
"unspecified": "未指定",
|
"unspecified": "未指定",
|
||||||
"added": "已添加",
|
"added": "已添加",
|
||||||
@@ -682,9 +685,9 @@
|
|||||||
"articleAttachmentHint": "附件必須上傳並插入到文章主體中才能顯示出來。",
|
"articleAttachmentHint": "附件必須上傳並插入到文章主體中才能顯示出來。",
|
||||||
"postVisibility": "可見性",
|
"postVisibility": "可見性",
|
||||||
"currentMembershipMember": "恆星計劃成員 · {}",
|
"currentMembershipMember": "恆星計劃成員 · {}",
|
||||||
"membershipPriceStellar": "需要用戶等級 3+,每月價格 1200 NSP",
|
"membershipPriceStellar": "需要用戶等級 20+,每月價格 1200 NSP",
|
||||||
"membershipPriceNova": "需要用戶等級 6+,每月價格 2400 NSP",
|
"membershipPriceNova": "需要用戶等級 40+,每月價格 2400 NSP",
|
||||||
"membershipPriceSupernova": "需要用戶等級 9+,每月價格 3600 NSP",
|
"membershipPriceSupernova": "需要用戶等級 60+,每月價格 3600 NSP",
|
||||||
"sharePostPhoto": "通過圖片分享帖子",
|
"sharePostPhoto": "通過圖片分享帖子",
|
||||||
"wouldYouLikeToNavigateToChat": "你想要前往聊天頁面嗎?",
|
"wouldYouLikeToNavigateToChat": "你想要前往聊天頁面嗎?",
|
||||||
"abuseReports": "舉報",
|
"abuseReports": "舉報",
|
||||||
@@ -1060,7 +1063,7 @@
|
|||||||
"failedToDeleteRecycledFiles": "已回收檔案刪除失敗",
|
"failedToDeleteRecycledFiles": "已回收檔案刪除失敗",
|
||||||
"upload": "上傳",
|
"upload": "上傳",
|
||||||
"deleteMessage": "刪除訊息",
|
"deleteMessage": "刪除訊息",
|
||||||
"deleteMessageConfirmation": "確定要刪除此郵件嗎?",
|
"deleteMessageConfirmation": "確定要刪除此郵件嗎?",
|
||||||
"customReaction": "自訂反應",
|
"customReaction": "自訂反應",
|
||||||
"customReactions": "自訂反應",
|
"customReactions": "自訂反應",
|
||||||
"stickerPlaceholder": "貼紙佔位符",
|
"stickerPlaceholder": "貼紙佔位符",
|
||||||
@@ -1131,348 +1134,417 @@
|
|||||||
"noReceivedGifts": "没有收到过礼物",
|
"noReceivedGifts": "没有收到过礼物",
|
||||||
"stellarGift": "恆星禮物",
|
"stellarGift": "恆星禮物",
|
||||||
"novaGift": "新星禮物",
|
"novaGift": "新星禮物",
|
||||||
"supernovaGift": "Supernova Gift",
|
"supernovaGift": "超新星訂閱",
|
||||||
"sameAsMembership": "Same as membership",
|
"sameAsMembership": "於成員相同",
|
||||||
"enterGiftCodeToRedeem": "Enter gift code to redeem",
|
"enterGiftCodeToRedeem": "輸入禮物程式碼以兌換",
|
||||||
"enterGiftCode": "Enter gift code",
|
"enterGiftCode": "輸入禮物程式碼",
|
||||||
"giftPurchased": "Gift Purchased!",
|
"giftPurchased": "已購買禮物!",
|
||||||
"shareCodeWithRecipient": "Share this code with the recipient to redeem the gift.",
|
"shareCodeWithRecipient": "與收件人分享此程式碼來兌換禮物。",
|
||||||
"openGiftAnyoneCanRedeem": "This is an open gift that anyone can redeem.",
|
"openGiftAnyoneCanRedeem": "這是一份任何人都可以兌換的公開禮物。",
|
||||||
"ok": "OK",
|
"ok": "好的",
|
||||||
"selectedRecipient": "Selected recipient",
|
"selectedRecipient": "選擇接收者",
|
||||||
"noRecipientSelected": "No recipient selected",
|
"noRecipientSelected": "沒有選中的接受者",
|
||||||
"thisWillBeAnOpenGift": "This will be an open gift",
|
"thisWillBeAnOpenGift": "這將是一份公開的禮物",
|
||||||
"personalMessage": "Personal Message",
|
"personalMessage": "個人信息",
|
||||||
"addPersonalMessageForRecipient": "Add a personal message for the recipient",
|
"addPersonalMessageForRecipient": "為收件人添加個人訊息",
|
||||||
"giftStatusCreated": "Created",
|
"giftStatusCreated": "已創建",
|
||||||
"giftStatusSent": "Sent",
|
"giftStatusSent": "發送",
|
||||||
"giftStatusRedeemed": "Redeemed",
|
"giftStatusRedeemed": "已兌換",
|
||||||
"giftStatusCancelled": "Cancelled",
|
"giftStatusCancelled": "已取消",
|
||||||
"giftStatusExpired": "Expired",
|
"giftStatusExpired": "已過期",
|
||||||
"giftStatusUnknown": "Unknown",
|
"giftStatusUnknown": "未知",
|
||||||
"giftCodeCopiedToClipboard": "Gift code copied to clipboard",
|
"giftCodeCopiedToClipboard": "禮物程式碼已經複製到剪貼簿",
|
||||||
"codeLabel": "Code: ",
|
"codeLabel": "程式碼:",
|
||||||
"subscriptionLabel": "Subscription: ",
|
"subscriptionLabel": "訂閱:",
|
||||||
"toLabel": "To: ",
|
"toLabel": "至:",
|
||||||
"fromLabel": "From: ",
|
"fromLabel": "從:",
|
||||||
"messageLabel": "Message: ",
|
"messageLabel": "消息:",
|
||||||
"giftRedeemed": "Gift Redeemed!",
|
"giftRedeemed": "禮物已兌換!",
|
||||||
"giftRedeemedSuccessfully": "You have successfully redeemed the gift. Your new subscription is now active.",
|
"giftRedeemedSuccessfully": "您已成功兌換了禮物。您的新訂閱現在已經生效。",
|
||||||
"cancelGift": "Cancel Gift",
|
"cancelGift": "取消禮物",
|
||||||
"cancelGiftConfirm": "Are you sure you want to cancel this gift? This action cannot be undone.",
|
"cancelGiftConfirm": "您確定要取消此禮物?此操作無法撤銷。",
|
||||||
"giftCancelledSuccessfully": "Gift cancelled successfully",
|
"giftCancelledSuccessfully": "禮物成功取消",
|
||||||
"createFund": "Create Fund",
|
"createFund": "創建支票",
|
||||||
"fundAmount": "Fund Amount",
|
"fundAmount": "支票金額",
|
||||||
"enterAmount": "Enter Amount",
|
"enterAmount": "輸入金額",
|
||||||
"selectCurrency": "Select Currency",
|
"selectCurrency": "選擇貨幣",
|
||||||
"splitType": "Split Type",
|
"splitType": "拆分類型",
|
||||||
"evenSplit": "Even Split",
|
"evenSplit": "平均拆分",
|
||||||
"equalAmountEach": "Equal amount for each recipient",
|
"equalAmountEach": "每個收款人的金額相同",
|
||||||
"randomSplit": "Random Split",
|
"randomSplit": "隨機拆分",
|
||||||
"randomAmountEach": "Random amount for each recipient",
|
"randomAmountEach": "每個收款人的金額隨機",
|
||||||
"recipientCount": "Recipient Count",
|
"recipientCount": "收款人總計",
|
||||||
"numberOfRecipients": "Number of Recipients",
|
"numberOfRecipients": "收款人數量",
|
||||||
"addPersonalMessageForRecipients": "Add a personal message for recipients",
|
"addPersonalMessageForRecipients": "為收款人添加個人信息",
|
||||||
"invalidAmount": "Invalid amount",
|
"invalidAmount": "無效的金額",
|
||||||
"invalidRecipientCount": "Invalid recipient count",
|
"invalidRecipientCount": "收款人數量無效",
|
||||||
"fundOverview": "Fund Overview",
|
"fundOverview": "支票概覽",
|
||||||
"totalFundsSent": "Total Funds Sent",
|
"totalFundsSent": "共發送支票",
|
||||||
"totalFundsReceived": "Total Funds Received",
|
"totalFundsReceived": "共領取支票",
|
||||||
"transactions": "Transactions",
|
"transactions": "交易",
|
||||||
"myFunds": "My Funds",
|
"myFunds": "我的支票",
|
||||||
"availableFunds": "Available Funds",
|
"availableFunds": "可用支票",
|
||||||
"fundStatusCreated": "Created",
|
"fundStatusCreated": "已創建",
|
||||||
"fundStatusPartial": "Partially Claimed",
|
"fundStatusPartial": "部分領取",
|
||||||
"fundStatusCompleted": "Fully Claimed",
|
"fundStatusCompleted": "已領完",
|
||||||
"fundStatusExpired": "Expired",
|
"fundStatusExpired": "已過期",
|
||||||
"fundStatusUnknown": "Unknown",
|
"fundStatusUnknown": "未知",
|
||||||
"recipients": "Recipients",
|
"recipients": "收款人",
|
||||||
"fundClaimedSuccessfully": "Fund claimed successfully!",
|
"fundClaimedSuccessfully": "支票成功領取!",
|
||||||
"claim": "Claim",
|
"claim": "領取",
|
||||||
"noFundsCreated": "No funds created yet",
|
"noFundsCreated": "還沒有創建的支票",
|
||||||
"createYourFirstFund": "Create your first fund to get started",
|
"createYourFirstFund": "創建您的第一個支票以開始",
|
||||||
"noAvailableFunds": "No available funds",
|
"noAvailableFunds": "暫無可用支票",
|
||||||
"fundsWillAppearHere": "Funds you can claim will appear here",
|
"fundsWillAppearHere": "您可以領取的支票將出現在這裡",
|
||||||
"fundCreatedSuccessfully": "Fund created successfully!",
|
"fundCreatedSuccessfully": "支票成功創建!",
|
||||||
"selectRecipients": "Select Recipients",
|
"selectRecipients": "選擇收款人",
|
||||||
"noRecipientsSelected": "No recipients selected",
|
"noRecipientsSelected": "沒有選擇收款人",
|
||||||
"selectRecipientsToSendFund": "Select recipients to send the fund to",
|
"selectRecipientsToSendFund": "選擇收款人將支票發送到",
|
||||||
"addRecipient": "Add Recipient",
|
"addRecipient": "添加收款人",
|
||||||
"addMoreRecipients": "Add More Recipients",
|
"addMoreRecipients": "添加更多收款人",
|
||||||
"transactionDetails": "Transaction Details",
|
"transactionDetails": "交易詳情",
|
||||||
"remarks": "Remarks",
|
"remarks": "備註",
|
||||||
"payer": "Payer",
|
"payer": "付款方",
|
||||||
"payee": "Payee",
|
"payee": "交易方",
|
||||||
"transactionType": "Transaction Type",
|
"transactionType": "交易類型",
|
||||||
"transfer": "Transfer",
|
"transfer": "轉帳",
|
||||||
"payment": "Payment",
|
"payment": "支付",
|
||||||
"systemWallet": "System Wallet",
|
"systemWallet": "系統錢包",
|
||||||
"date": "Date",
|
"date": "日期",
|
||||||
"createTransfer": "Create Transfer",
|
"createTransfer": "創建交易",
|
||||||
"transferAmount": "Transfer Amount",
|
"transferAmount": "交易金額",
|
||||||
"selectPayee": "Select Payee",
|
"selectPayee": "請選擇收款人",
|
||||||
"selectedPayee": "Selected Payee",
|
"selectedPayee": "選定的收款人",
|
||||||
"noPayeeSelected": "No payee selected",
|
"noPayeeSelected": "沒有選擇收款人",
|
||||||
"selectPayeeToTransfer": "Select payee to transfer to",
|
"selectPayeeToTransfer": "選擇要轉帳的收款人",
|
||||||
"addRemark": "Add Remark",
|
"addRemark": "添加備註",
|
||||||
"transferRemark": "Transfer Remark",
|
"transferRemark": "交易備註",
|
||||||
"addRemarkForTransfer": "Add remark for transfer",
|
"addRemarkForTransfer": "為轉帳添加備註",
|
||||||
"enterPinToConfirmTransfer": "Enter your 6-digit PIN to confirm transfer",
|
"enterPinToConfirmTransfer": "輸入您的 6 位PIN碼以確認轉帳",
|
||||||
"transferCreatedSuccessfully": "Transfer created successfully!",
|
"transferCreatedSuccessfully": "轉帳成功創建",
|
||||||
"postUpdate": "Update",
|
"postUpdate": "更新",
|
||||||
"fileMetadata": "File Metadata",
|
"fileMetadata": "檔案資訊",
|
||||||
"resend": "Resend",
|
"resend": "重新發送",
|
||||||
"fileInfoTitle": "File Information",
|
"fileInfoTitle": "檔案信息",
|
||||||
"download": "Download",
|
"download": "下載",
|
||||||
"info": "Info",
|
"info": "信息",
|
||||||
"noStickers": "No Stickers",
|
"noStickers": "沒有貼圖",
|
||||||
"noStickersInPack": "This pack does not contains stickers",
|
"noStickersInPack": "這個包不包含貼圖",
|
||||||
"noStickerPacks": "No Sticker Packs",
|
"noStickerPacks": "沒有貼圖包",
|
||||||
"refresh": "Refresh",
|
"refresh": "刷新",
|
||||||
"spoiler": "Spoiler",
|
"spoiler": "已隱藏",
|
||||||
"activityHeatmap": "Activity Heatmap",
|
"activityHeatmap": "活动热力图",
|
||||||
"custom": "Custom",
|
"custom": "自定義",
|
||||||
"usernameColor": "Username Color",
|
"usernameColor": "用戶名顏色",
|
||||||
"colorType": "Color Type",
|
"colorType": "顏色類型",
|
||||||
"plain": "Plain",
|
"plain": "純色",
|
||||||
"gradient": "Gradient",
|
"gradient": "漸變",
|
||||||
"colorValue": "Color Value",
|
"colorValue": "色值",
|
||||||
"gradientDirection": "Gradient Direction",
|
"gradientDirection": "漸變方向",
|
||||||
"gradientDirectionToRight": "To Right",
|
"gradientDirectionToRight": "向右",
|
||||||
"gradientDirectionToLeft": "To Left",
|
"gradientDirectionToLeft": "向左",
|
||||||
"gradientDirectionToBottom": "To Bottom",
|
"gradientDirectionToBottom": "向底部",
|
||||||
"gradientDirectionToTop": "To Top",
|
"gradientDirectionToTop": "向上",
|
||||||
"gradientDirectionToBottomRight": "To Bottom Right",
|
"gradientDirectionToBottomRight": "向右下角",
|
||||||
"gradientDirectionToBottomLeft": "To Bottom Left",
|
"gradientDirectionToBottomLeft": "向左下角",
|
||||||
"gradientDirectionToTopRight": "To Top Right",
|
"gradientDirectionToTopRight": "向右上角",
|
||||||
"gradientDirectionToTopLeft": "To Top Left",
|
"gradientDirectionToTopLeft": "向左下角",
|
||||||
"gradientColors": "Gradient Colors",
|
"gradientColors": "漸變顏色",
|
||||||
"color": "Color",
|
"color": "顏色",
|
||||||
"addColor": "Add Color",
|
"addColor": "添加顏色",
|
||||||
"availableWithYourPlan": "Available with your plan",
|
"availableWithYourPlan": "隨您的方案提供",
|
||||||
"upgradeRequired": "Upgrade required",
|
"upgradeRequired": "需要升級",
|
||||||
"settingsDisableAnimation": "Disable Animation",
|
"settingsDisableAnimation": "停用動畫",
|
||||||
"addTag": "Add Tag",
|
"addTag": "添加標籤",
|
||||||
"accountConnectionProviderSpotify": "Spotify",
|
"accountConnectionProviderSpotify": "Spotify",
|
||||||
"accountConnectionProviderSteam": "Steam",
|
"accountConnectionProviderSteam": "Steam",
|
||||||
"timezoneNotFound": "Time zone not found",
|
"timezoneNotFound": "找不到時區",
|
||||||
"awardPoints": "Awarded {} points",
|
"awardPoints": "獎賞 {} 點",
|
||||||
"postFeaturedOn": "Post featured on {}",
|
"postFeaturedOn": "帖文在 {} 被精選",
|
||||||
"messageSentAt": "Sent at {}",
|
"messageSentAt": "發送在 {}",
|
||||||
"myTickets": "My Tickets",
|
"myTickets": "我的彩票",
|
||||||
"drawHistory": "Draw History",
|
"drawHistory": "開獎歷史",
|
||||||
"lottery": "Lottery",
|
"lottery": "彩票",
|
||||||
"noLotteryTickets": "No lottery tickets yet",
|
"noLotteryTickets": "還沒有彩票",
|
||||||
"buyYourFirstTicket": "Buy your first lottery ticket to get started!",
|
"buyYourFirstTicket": "購買您的第一張彩票以開始!",
|
||||||
"buyTicket": "Buy Ticket",
|
"buyTicket": "買彩票",
|
||||||
"ticketNumbers": "Numbers: {}, Special: {}",
|
"ticketNumbers": "數字:{},特殊數字:{}",
|
||||||
"cost": "Cost",
|
"cost": "花費",
|
||||||
"multiplier": "Multiplier",
|
"multiplier": "倍率",
|
||||||
"prizeWon": "Prize Won",
|
"prizeWon": "獲勝者",
|
||||||
"pending": "Pending",
|
"pending": "待開獎",
|
||||||
"drawn": "Drawn",
|
"drawn": "已開獎",
|
||||||
"won": "Won",
|
"won": "獲勝",
|
||||||
"lost": "Lost",
|
"lost": "失敗",
|
||||||
"noDrawHistory": "No draw history yet",
|
"noDrawHistory": "還沒有開獎曆史",
|
||||||
"buyLotteryTicket": "Buy Lottery Ticket",
|
"buyLotteryTicket": "購買彩票",
|
||||||
"selectNumbers": "Select Numbers",
|
"selectNumbers": "選擇數字",
|
||||||
"select5UniqueNumbers": "Select 5 unique numbers",
|
"select5UniqueNumbers": "選擇 5 個不同的數字",
|
||||||
"selectSpecialNumber": "Select Special Number",
|
"selectSpecialNumber": "選擇特殊數字",
|
||||||
"selectMultiplier": "Select Multiplier",
|
"selectMultiplier": "選擇倍率",
|
||||||
"baseCost": "Base Cost",
|
"baseCost": "基礎花費",
|
||||||
"totalCost": "Total Cost",
|
"totalCost": "總費用",
|
||||||
"prizeStructure": "Prize Structure",
|
"prizeStructure": "獎金分級",
|
||||||
"enterPinToConfirmPurchase": "Enter your PIN to confirm purchase",
|
"enterPinToConfirmPurchase": "輸入您的 PIN 碼以確認購買",
|
||||||
"ticketPurchasedSuccessfully": "Ticket purchased successfully!",
|
"ticketPurchasedSuccessfully": "彩票購買成功!",
|
||||||
"winningNumbers": "Winning Numbers",
|
"winningNumbers": "獲勝數字",
|
||||||
"specialNumber": "Special Number",
|
"specialNumber": "特殊數字",
|
||||||
"totalTickets": "Total Tickets",
|
"totalTickets": "總售出票數",
|
||||||
"totalWinners": "Total Winners",
|
"totalWinners": "總中獎者",
|
||||||
"prizePool": "Prize Pool",
|
"prizePool": "獎池",
|
||||||
"enterPinToConfirmPayment": "Enter your PIN code to confirm payment",
|
"enterPinToConfirmPayment": "輸入您的 PIN 碼以確認交易",
|
||||||
"purchase": "Purchase",
|
"purchase": "購買",
|
||||||
"multiplierLabel": "Multiplier",
|
"multiplierLabel": "倍率",
|
||||||
"specialOnly": "Special Only",
|
"specialOnly": "僅特殊數字",
|
||||||
"matches": "Matches",
|
"matches": "場次",
|
||||||
"thoughtDefaultTopic": "Reflection",
|
"thoughtDefaultTopic": "尋思",
|
||||||
"thoughtAiName": "SN-chan",
|
"thoughtAiName": "SN醬",
|
||||||
"thoughtUserName": "You",
|
"thoughtUserName": "你",
|
||||||
"thoughtStreamingHint": "Sn-chan is thinking...",
|
"thoughtStreamingHint": "SN醬正在思考……",
|
||||||
"thoughtInputHint": "Ask sn-chan anything...",
|
"thoughtInputHint": "問SN醬一些東西……",
|
||||||
"thoughtNewConversation": "Start New Conversation",
|
"thoughtNewConversation": "開始新對話",
|
||||||
"thoughtParseError": "Failed to parse AI response",
|
"thoughtParseError": "解析 AI 響應失敗",
|
||||||
"thoughtFunctionCall": "Use {}",
|
"thoughtFunctionCall": "使用 {}",
|
||||||
"aiThought": "AI Thought",
|
"aiThought": "尋思",
|
||||||
"aiThoughtTitle": "Let sn-chan think",
|
"aiThoughtTitle": "讓SN醬思考",
|
||||||
"postReferenceUnavailable": "Referenced post is unavailable",
|
"postReferenceUnavailable": "應用的帖子不可用",
|
||||||
"fabLocation": "FAB Location",
|
"fabLocation": "底部菜單按鈕位置",
|
||||||
"activities": "Activities",
|
"activities": "活動",
|
||||||
"presenceTypeGaming": "Playing",
|
"presenceTypeGaming": "正在玩",
|
||||||
"presenceTypeMusic": "Listening to Music",
|
"presenceTypeMusic": "正在聽音樂",
|
||||||
"presenceTypeWorkout": "Working out",
|
"presenceTypeWorkout": "鍛煉中",
|
||||||
"articleCompose": "Compose Article",
|
"articleCompose": "撰寫文章",
|
||||||
"backToHub": "Back to Hub",
|
"backToHub": "返回至主頁",
|
||||||
"advancedFilters": "Advanced Filters",
|
"advancedFilters": "高級篩選",
|
||||||
"searchPosts": "Search Posts",
|
"searchPosts": "搜索帖子",
|
||||||
"sortBy": "Sort by",
|
"sortBy": "排序方式",
|
||||||
"fromDate": "From Date",
|
"fromDate": "起始日期",
|
||||||
"toDate": "To Date",
|
"toDate": "截止日期",
|
||||||
"popularity": "Popularity",
|
"popularity": "按熱度",
|
||||||
"descendingOrder": "Descending Order",
|
"descendingOrder": "降序排序",
|
||||||
"selectDate": "Select Date",
|
"selectDate": "選擇日期",
|
||||||
"pinnedPosts": "Pinned Posts",
|
"pinnedPosts": "已置頂的帖子",
|
||||||
"customReactionHint": "Custom Reaction allow you to use user uploaded stickers as the symbol of the reaction for the post. Exclusive for Stellar Program members.",
|
"customReactionHint": "自訂反應允許你使用用戶上傳貼紙作為帖子反應的符號,需要恆星計劃訂閱。",
|
||||||
"publicationSites": "Publication Sites",
|
"publicationSites": "發佈者網站",
|
||||||
"uploadTasks": "Upload Tasks",
|
"uploadTasks": "上傳任務",
|
||||||
"thoughtFunctionCallBegin": "Calling tool {}",
|
"thoughtFunctionCallBegin": "調用工具 {}",
|
||||||
"thoughtFunctionCallFinish": "{} responded",
|
"thoughtFunctionCallFinish": "工具 {}",
|
||||||
"thoughtUnpaidHint": "Thinking unavaiable due to unpaid orders",
|
"thoughtUnpaidHint": "尋思因為有未支付的訂單而被禁用",
|
||||||
"more": "More",
|
"more": "更多",
|
||||||
"collapse": "Collapse",
|
"collapse": "折疊",
|
||||||
"pollConfirmDiscard": "Are you sure you want to leave? All the poll data you're editing will not be saved.",
|
"pollConfirmDiscard": "您確定要離開嗎?您編輯的所有資料都不會被保存。",
|
||||||
"discard": "Discard",
|
"discard": "Discard",
|
||||||
"fund": "Fund",
|
"fund": "支票",
|
||||||
"fundsRecent": "Recent Funds",
|
"fundsRecent": "最近的支票",
|
||||||
"fundCreateNew": "Create New",
|
"fundCreateNew": "創建新的",
|
||||||
"fundCreateNewHint": "Create a new fund for your message. Select recipients and amount.",
|
"fundCreateNewHint": "為您的消息創建一個新的紅包。選擇接收者和金額。",
|
||||||
"amountOfSplits": "Amount of Splits",
|
"amountOfSplits": "份數",
|
||||||
"enterNumberOfSplits": "Enter Splits Amount",
|
"enterNumberOfSplits": "單份金額",
|
||||||
"orCreateWith": "Or\ncreate with",
|
"orCreateWith": "或\n使用第三方賬戶登錄",
|
||||||
"unindexedFiles": "Unindexed files",
|
"unindexedFiles": "未索引的檔案",
|
||||||
"folder": "Folder",
|
"folder": "文件夾",
|
||||||
"clearCompleted": "Clear Completed",
|
"clearCompleted": "清除已經完成的",
|
||||||
"uploadSuccess": "Upload successful!",
|
"uploadSuccess": "上傳成功!",
|
||||||
"wouldYouLikeToViewFile": "Would you like to view the file?",
|
"wouldYouLikeToViewFile": "您想查看檔案嗎?",
|
||||||
"contentCantEmpty": "Content cannot be empty",
|
"contentCantEmpty": "內容不能為空",
|
||||||
"features": "Features",
|
"features": "功能",
|
||||||
"unnamed": "Unnamed",
|
"unnamed": "未命名",
|
||||||
"fundEnvelopeLoadFailed": "Failed to load fund envelope",
|
"fundEnvelopeLoadFailed": "載入支票信封失敗",
|
||||||
"fundEnvelope": "Fund Envelope",
|
"fundEnvelope": "支票信封",
|
||||||
"fundEnvelopeRemaining": "Remaining: {} {}",
|
"fundEnvelopeRemaining": "剩餘:{} {}",
|
||||||
"fundEnvelopeSplit": "Split: {}",
|
"fundEnvelopeSplit": "拆分:{}",
|
||||||
"fundEnvelopeSplitEvenly": "Evenly",
|
"fundEnvelopeSplitEvenly": "均分",
|
||||||
"fundEnvelopeSplitRandomly": "Randomly",
|
"fundEnvelopeSplitRandomly": "隨機",
|
||||||
"fundEnvelopeClaimSuccess": "Fund claimed successfully!",
|
"fundEnvelopeClaimSuccess": "支票領取成功!",
|
||||||
"fundEnvelopeStatusCreated": "Created",
|
"fundEnvelopeStatusCreated": "已創建",
|
||||||
"fundEnvelopeStatusPartial": "Partially Claimed",
|
"fundEnvelopeStatusPartial": "已領取部分",
|
||||||
"fundEnvelopeStatusCompleted": "Fully Claimed",
|
"fundEnvelopeStatusCompleted": "已全部領取",
|
||||||
"fundEnvelopeStatusExpired": "Expired",
|
"fundEnvelopeStatusExpired": "已過期",
|
||||||
"fundEnvelopeStatusUnknown": "Unknown",
|
"fundEnvelopeStatusUnknown": "未知",
|
||||||
"fundEnvelopeRecipients": "Recipients ({}/{} claimed)",
|
"fundEnvelopeRecipients": "收款人 ({}/{}已領取)",
|
||||||
"fundEnvelopeExpiredDaysAgo": {
|
"fundEnvelopeExpiredDaysAgo": {
|
||||||
"one": "Expired {} day ago",
|
"one": "{}天前過期",
|
||||||
"other": "Expired {} days ago"
|
"other": "{}天前過期"
|
||||||
},
|
},
|
||||||
"fundEnvelopeExpiresSoon": "Expires soon",
|
"fundEnvelopeExpiresSoon": "即將過期",
|
||||||
"fundEnvelopeExpiresInHours": {
|
"fundEnvelopeExpiresInHours": {
|
||||||
"one": "Expires in {} hour",
|
"one": "{}小時後過期",
|
||||||
"other": "Expires in {} hours"
|
"other": "{}小時後過期"
|
||||||
},
|
},
|
||||||
"fundEnvelopeExpiresInDays": {
|
"fundEnvelopeExpiresInDays": {
|
||||||
"one": "Expires in {} day",
|
"one": "{}天後過期",
|
||||||
"other": "Expires in {} days"
|
"other": "{}天後過期"
|
||||||
},
|
},
|
||||||
"fundEnvelopeRemainingWithSplits": "{} {} / {} splits",
|
"fundEnvelopeRemainingWithSplits": "{} {} / {} 份",
|
||||||
"fundEnvelopeUnknownUser": "Unknown User",
|
"fundEnvelopeUnknownUser": "未知用戶",
|
||||||
"deleteSite": "Delete Site",
|
"deleteSite": "刪除網站",
|
||||||
"deleteSiteConfirm": "Are you sure you want to delete this site?",
|
"deleteSiteConfirm": "您確定要刪除此網站嗎?",
|
||||||
"siteDeletedSuccess": "Site deleted successfully",
|
"siteDeletedSuccess": "網站成功刪除",
|
||||||
"siteSlug": "Slug",
|
"siteSlug": "標識符",
|
||||||
"siteSlugHint": "my-site",
|
"siteSlugHint": "我的站點",
|
||||||
"siteSlugRequired": "Please enter a slug",
|
"siteSlugRequired": "請輸入一個標識符",
|
||||||
"siteSlugInvalid": "Slug can only contain lowercase letters, numbers, and dashes",
|
"siteSlugInvalid": "標識符只能包含小寫字母、數字和連字符",
|
||||||
"siteName": "Site Name",
|
"siteName": "網站名稱",
|
||||||
"siteNameHint": "My Publication Site",
|
"siteNameHint": "我的發佈者網站",
|
||||||
"siteNameRequired": "Please enter a site name",
|
"siteNameRequired": "請輸入一個站點名稱",
|
||||||
"siteMode": "Mode",
|
"siteMode": "模式",
|
||||||
"siteModeFullyManaged": "Fully Managed",
|
"siteModeFullyManaged": "全託管",
|
||||||
"siteModeSelfManaged": "Self-Managed",
|
"siteModeSelfManaged": "自託管",
|
||||||
"editPublicationSite": "Edit Publication Site",
|
"editPublicationSite": "編輯發佈者網站",
|
||||||
"deletePublicationSite": "Delete Publication Site",
|
"deletePublicationSite": "刪除發佈者網站",
|
||||||
"publicationSiteSavedSuccess": "Publication site saved successfully",
|
"publicationSiteSavedSuccess": "發佈者網站保存成功",
|
||||||
"publicationSiteDeleteConfirm": "Are you sure you want to delete this publication site? This action cannot be undone.",
|
"publicationSiteDeleteConfirm": "您確定要刪除此發佈者網站嗎?此操作不能撤銷。",
|
||||||
"publicationSiteDeletedSuccess": "Publication site deleted successfully",
|
"publicationSiteDeletedSuccess": "發佈者網站成功刪除",
|
||||||
"newPublicationSite": "New Publication Site",
|
"newPublicationSite": "新建發佈者網站",
|
||||||
"siteDetails": "Site Details",
|
"siteDetails": "網站描述",
|
||||||
"siteInformation": "Site Information",
|
"siteInformation": "網站信息",
|
||||||
"siteDomain": "Domain",
|
"siteDomain": "域名",
|
||||||
"siteCreated": "Created",
|
"siteCreated": "創建于",
|
||||||
"siteUpdated": "Updated",
|
"siteUpdated": "更新于",
|
||||||
"failedToLoadSite": "Failed to load site",
|
"failedToLoadSite": "加載網站失敗",
|
||||||
"sitePages": "Pages",
|
"sitePages": "頁面",
|
||||||
"noPagesYet": "No pages yet",
|
"noPagesYet": "還沒有頁面",
|
||||||
"createFirstPage": "Create your first page to get started",
|
"createFirstPage": "創建您的第一個頁面以開始",
|
||||||
"failedToLoadPages": "Failed to load pages",
|
"failedToLoadPages": "加載頁面失敗",
|
||||||
"fileManagement": "File Management",
|
"fileManagement": "檔案管理器",
|
||||||
"siteFiles": "Files",
|
"siteFiles": "檔案",
|
||||||
"siteFolder": "Folder",
|
"siteFolder": "資料夾",
|
||||||
"siteRoot": "Root",
|
"siteRoot": "根",
|
||||||
"noFilesUploadedYet": "No files uploaded yet",
|
"noFilesUploadedYet": "尚未上傳任何檔案",
|
||||||
"uploadFirstFile": "Upload your first file to get started",
|
"uploadFirstFile": "上傳您的第一個檔案以開始",
|
||||||
"failedToLoadFiles": "Failed to load files",
|
"failedToLoadFiles": "加載檔案失敗",
|
||||||
"noFilesFoundInFolder": "No files found in the selected folder",
|
"noFilesFoundInFolder": "在選擇的資料夾中沒有檔案",
|
||||||
"fileActions": "File Actions",
|
"fileActions": "檔案選項",
|
||||||
"purgeFiles": "Purge Files",
|
"purgeFiles": "清除檔案",
|
||||||
"purgeFilesDescription": "Remove all uploaded files from the site",
|
"purgeFilesDescription": "從這個網站刪除全部文件",
|
||||||
"deploySite": "Deploy Site",
|
"deploySite": "部署網站",
|
||||||
"deploySiteDescription": "Upload and deploy a new version from ZIP archive",
|
"deploySiteDescription": "從ZIP存檔上傳和部署新版本",
|
||||||
"confirmPurge": "Confirm Purge",
|
"confirmPurge": "確認清空",
|
||||||
"purgeFilesConfirm": "This will permanently delete all files uploaded to this site. This action cannot be undone. Are you sure you want to continue?",
|
"purgeFilesConfirm": "這將永久刪除上傳到本網站的所有檔案。此操作無法復原。您確定要繼續嗎?",
|
||||||
"purgeAllFiles": "Purge All Files",
|
"purgeAllFiles": "清除所有文檔案",
|
||||||
"allFilesPurgedSuccess": "All files purged successfully",
|
"allFilesPurgedSuccess": "全部檔案成功清空",
|
||||||
"failedToPurgeFiles": "Failed to purge files: {}",
|
"failedToPurgeFiles": "清除檔案失敗:{}",
|
||||||
"siteDeployedSuccess": "Site deployed successfully",
|
"siteDeployedSuccess": "網站成功部署",
|
||||||
"failedToDeploySite": "Failed to deploy site: {}",
|
"failedToDeploySite": "部署網站失敗:{}",
|
||||||
"createPage": "Create Page",
|
"createPage": "創建頁面",
|
||||||
"editPage": "Edit Page",
|
"editPage": "編輯頁面",
|
||||||
"pageType": "Page Type",
|
"pageType": "頁面類型",
|
||||||
"htmlPage": "HTML Page",
|
"htmlPage": "HTML 頁面",
|
||||||
"redirectPage": "Redirect Page",
|
"redirectPage": "重定向頁面",
|
||||||
"pageTypeRequired": "Please select a page type",
|
"pageTypeRequired": "請選擇一個頁面類型",
|
||||||
"pagePath": "Page Path",
|
"pagePath": "頁面路徑",
|
||||||
"pagePathHint": "/about, /contact, etc.",
|
"pagePathHint": "例如/about,/contact等",
|
||||||
"pagePathRequired": "Please enter a page path",
|
"pagePathRequired": "請輸入一個頁面路徑",
|
||||||
"pagePathInvalid": "Page path can only contain letters, numbers, hyphens, underscores, and slashes",
|
"pagePathInvalid": "頁面路徑只能包含字母、數字、連字符、底線和斜線",
|
||||||
"pagePathMustStartWithSlash": "Page path must start with /",
|
"pagePathMustStartWithSlash": "頁面路徑以/開始",
|
||||||
"pagePathNoConsecutiveSlashes": "Page path cannot have consecutive slashes",
|
"pagePathNoConsecutiveSlashes": "頁面路徑不能有連續的斜線",
|
||||||
"pageTitle": "Page Title",
|
"pageTitle": "頁面標題",
|
||||||
"pageTitleHint": "About Us, Contact, etc.",
|
"pageTitleHint": "例如About Us,Contact等",
|
||||||
"pageTitleRequired": "Please enter a page title",
|
"pageTitleRequired": "請輸入一個頁面標題",
|
||||||
"pageContentHtml": "Page Content (HTML)",
|
"pageContentHtml": "頁面內容(HTML)",
|
||||||
"pageContentHint": "<h1>Hello World</h1><p>This is my page content...</p>",
|
"pageContentHint": "<h1> Hello World</h1><p>這是我的頁面內容…</p>",
|
||||||
"pageContentRequired": "Please enter HTML content for the page",
|
"pageContentRequired": "請為頁面輸入HTML內容",
|
||||||
"redirectTarget": "Redirect Target",
|
"redirectTarget": "重定向目標",
|
||||||
"redirectTargetHint": "/new-page, https://example.com, etc.",
|
"redirectTargetHint": "例如/new-page,https://example.com等",
|
||||||
"redirectTargetRequired": "Please enter a redirect target",
|
"redirectTargetRequired": "請輸入一個重定向目標",
|
||||||
"redirectTargetInvalid": "Target must be a relative path (/) or absolute URL (http/https)",
|
"redirectTargetInvalid": "目標必須是相對路徑(/)或絕對 URL(http/https)",
|
||||||
"deletePage": "Delete Page",
|
"deletePage": "刪除頁面",
|
||||||
"deletePageConfirm": "Are you sure you want to delete this page?",
|
"deletePageConfirm": "您確定要刪除此頁面嗎?",
|
||||||
"savePage": "Save Page",
|
"savePage": "保存頁面",
|
||||||
"pageCreatedSuccess": "Page created successfully",
|
"pageCreatedSuccess": "頁面創建成功",
|
||||||
"pageUpdatedSuccess": "Page updated successfully",
|
"pageUpdatedSuccess": "頁面更新成功",
|
||||||
"pageDeletedSuccess": "Page deleted successfully",
|
"pageDeletedSuccess": "頁面刪除成功",
|
||||||
"uploadFiles": "Upload Files",
|
"uploadFiles": "上傳檔案",
|
||||||
"uploadPath": "Upload Path",
|
"uploadPath": "上傳路徑",
|
||||||
"uploadPathHint": "/ (root) or /assets/images/",
|
"uploadPathHint": "/ (根目錄) 或 /assets/images/",
|
||||||
"uploadPathRequired": "Please enter an upload path",
|
"uploadPathRequired": "請輸入一個上傳路徑",
|
||||||
"uploadPathMustStartWithSlash": "Path must start with /",
|
"uploadPathMustStartWithSlash": "路徑以/開始",
|
||||||
"uploadPathNoSpaces": "Path cannot contain spaces",
|
"uploadPathNoSpaces": "路徑不能包含空格",
|
||||||
"uploadPathNoConsecutiveSlashes": "Path cannot have consecutive slashes",
|
"uploadPathNoConsecutiveSlashes": "路徑不能包含連續的斜槓",
|
||||||
"percentCompleted": "{}% completed",
|
"percentCompleted": "{}%已完成",
|
||||||
"filesToUpload": "{} files to upload",
|
"filesToUpload": "{} 個檔案要上傳",
|
||||||
"fileSizeKb": "Size: {} KB",
|
"fileSizeKb": "大小:{} KB",
|
||||||
"uploadingEllipsis": "Uploading...",
|
"uploadingEllipsis": "上傳中……",
|
||||||
"uploadFilesCount": {
|
"uploadFilesCount": {
|
||||||
"one": "Upload {} File",
|
"one": "上傳 {} 個檔案",
|
||||||
"other": "Upload {} Files"
|
"other": "上傳 {} 個檔案"
|
||||||
},
|
},
|
||||||
"allUploadsCompleted": "All uploads completed",
|
"allUploadsCompleted": "上傳全部完成",
|
||||||
"someUploadsFailed": "Some uploads failed",
|
"someUploadsFailed": "部分上傳失敗",
|
||||||
"uploadingInProgress": "Uploading in progress",
|
"uploadingInProgress": "正在上傳",
|
||||||
"readyToUpload": "Ready to upload",
|
"readyToUpload": "準備好上傳",
|
||||||
"allFilesUploadedSuccess": "All files uploaded successfully",
|
"allFilesUploadedSuccess": "全部檔案完成上傳",
|
||||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
"lotteryLastNumberSpecial": "最後一個選擇的數字將是您的特殊數字。",
|
||||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
"lotteryMultiplierRequired": "請輸入一個倍率",
|
||||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
"lotteryMultiplierRange": "倍率需要在1到10之間",
|
||||||
"dropToShare": "Drop to share"
|
"dropToShare": "拖拽以分享",
|
||||||
|
"affiliationSpell": "Affiliation Spell",
|
||||||
|
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||||
|
"friendsOnline": "Friends Online",
|
||||||
|
"createAccountAlmostThere": "Almost There",
|
||||||
|
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||||
|
"createAccountNotice": "Things you need to know before you create an account:",
|
||||||
|
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||||
|
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||||
|
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||||
|
"createAccountProfile": "Create your profile",
|
||||||
|
"createAccountToS": "Review Terms & Conditions",
|
||||||
|
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||||
|
"realmsDescription": "Manage realms you've joined.",
|
||||||
|
"exploreDescription": "Explore contents on the Solar Network.",
|
||||||
|
"accountDescription": "Information about your account.",
|
||||||
|
"chatDescription": "Group Chats and Direct Messages",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
|
"appSettingsDescription": "Customize your app.",
|
||||||
|
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||||
|
"walletDescription": "Your source point wallet.",
|
||||||
|
"relationshipsDescription": "Friends and connections.",
|
||||||
|
"notificationsDescription": "See what's happended related to you recently.",
|
||||||
|
"settingsFestivalFeatures": "Festival Limited Features",
|
||||||
|
"categoriesAndTags": "Categories & Tags",
|
||||||
|
"webArticlesStandDescription": "Explore external sites articles.",
|
||||||
|
"aboutDescription": "Learn more about the Solar Network.",
|
||||||
|
"abuseReportsDescription": "View and manage abuse reports.",
|
||||||
|
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||||
|
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||||
|
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||||
|
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||||
|
"levelingDescription": "See your leveling progress and history.",
|
||||||
|
"notableDayToday": "{} is today!",
|
||||||
|
"authSessionLogout": "Logout Session",
|
||||||
|
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||||
|
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||||
|
"postComposeDescription": "Compose a new post",
|
||||||
|
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||||
|
"accountActivationAlert": "Activate your account",
|
||||||
|
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||||
|
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||||
|
"accountActivationResend": "Resend",
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"noFurtherData": "No further data",
|
||||||
|
"searchAnything": "Search Anything...",
|
||||||
|
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||||
|
"mostRecent": "Most Recent",
|
||||||
|
"noNotificationsYet": "No notifications yet",
|
||||||
|
"recentChats": "Recent Chats",
|
||||||
|
"noFeaturedPostsAvailable": "No featured posts available",
|
||||||
|
"searchChatsAndPages": "Search chats and pages...",
|
||||||
|
"dashboard": "Dashboard",
|
||||||
|
"dashboardDescription": "All your data in one place.",
|
||||||
|
"postTagsCategories": "Post Tags and Categories",
|
||||||
|
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||||
|
"debugLogs": "Debug Logs",
|
||||||
|
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||||
|
"pinChatRoom": "Pin Chat Room",
|
||||||
|
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||||
|
"chatRoomPinned": "Chat room pinned successfully.",
|
||||||
|
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||||
|
"pinnedChatRoom": "Pinned Rooms",
|
||||||
|
"settingsGroupedChatList": "Grouped Chat List",
|
||||||
|
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||||
|
"settingsDashSearchEngine": "Search Engine for web",
|
||||||
|
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||||
|
"settingsDefaultScreen": "Default Screen",
|
||||||
|
"notableDayChristmas": "Christmas",
|
||||||
|
"notableDayNewYear": "New Year"
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
platform :ios, '15.0'
|
platform :ios, '16.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- Alamofire (5.11.0)
|
- Alamofire (5.11.0)
|
||||||
|
- audio_session (0.0.1):
|
||||||
|
- Flutter
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- croppy (0.0.1):
|
- croppy (0.0.1):
|
||||||
@@ -125,6 +127,8 @@ PODS:
|
|||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- PromisesSwift (~> 2.1)
|
- PromisesSwift (~> 2.1)
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
|
- flutter_app_intents (0.1.0):
|
||||||
|
- Flutter
|
||||||
- flutter_app_update (0.0.1):
|
- flutter_app_update (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_inappwebview_ios (0.0.1):
|
- flutter_inappwebview_ios (0.0.1):
|
||||||
@@ -217,6 +221,9 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- irondash_engine_context (0.0.1):
|
- irondash_engine_context (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- just_audio (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
- KeychainAccess (4.2.2)
|
- KeychainAccess (4.2.2)
|
||||||
- Kingfisher (8.6.2)
|
- Kingfisher (8.6.2)
|
||||||
- KingfisherWebP (1.7.2):
|
- KingfisherWebP (1.7.2):
|
||||||
@@ -269,6 +276,8 @@ PODS:
|
|||||||
- PromisesObjC (= 2.4.0)
|
- PromisesObjC (= 2.4.0)
|
||||||
- protocol_handler_ios (0.0.1):
|
- protocol_handler_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- quick_actions_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
- receive_sharing_intent (1.8.1):
|
- receive_sharing_intent (1.8.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- record_ios (1.1.0):
|
- record_ios (1.1.0):
|
||||||
@@ -320,12 +329,16 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- video_thumbnail (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- libwebp
|
||||||
- wakelock_plus (0.0.1):
|
- wakelock_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- WebRTC-SDK (137.7151.04)
|
- WebRTC-SDK (137.7151.04)
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- Alamofire
|
- Alamofire
|
||||||
|
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
@@ -336,6 +349,7 @@ DEPENDENCIES:
|
|||||||
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
||||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
|
- flutter_app_intents (from `.symlinks/plugins/flutter_app_intents/ios`)
|
||||||
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
|
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
|
||||||
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
||||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||||
@@ -349,6 +363,7 @@ DEPENDENCIES:
|
|||||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
||||||
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
||||||
|
- just_audio (from `.symlinks/plugins/just_audio/darwin`)
|
||||||
- Kingfisher (~> 8.0)
|
- Kingfisher (~> 8.0)
|
||||||
- KingfisherWebP
|
- KingfisherWebP
|
||||||
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
|
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
|
||||||
@@ -362,6 +377,7 @@ DEPENDENCIES:
|
|||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
||||||
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
|
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
|
||||||
|
- quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`)
|
||||||
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
||||||
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
||||||
- sensors_plus (from `.symlinks/plugins/sensors_plus/ios`)
|
- sensors_plus (from `.symlinks/plugins/sensors_plus/ios`)
|
||||||
@@ -373,6 +389,7 @@ DEPENDENCIES:
|
|||||||
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
|
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
|
||||||
- syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`)
|
- syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
- video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`)
|
||||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
@@ -408,6 +425,8 @@ SPEC REPOS:
|
|||||||
- WebRTC-SDK
|
- WebRTC-SDK
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
|
audio_session:
|
||||||
|
:path: ".symlinks/plugins/audio_session/ios"
|
||||||
connectivity_plus:
|
connectivity_plus:
|
||||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||||
croppy:
|
croppy:
|
||||||
@@ -428,6 +447,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
|
flutter_app_intents:
|
||||||
|
:path: ".symlinks/plugins/flutter_app_intents/ios"
|
||||||
flutter_app_update:
|
flutter_app_update:
|
||||||
:path: ".symlinks/plugins/flutter_app_update/ios"
|
:path: ".symlinks/plugins/flutter_app_update/ios"
|
||||||
flutter_inappwebview_ios:
|
flutter_inappwebview_ios:
|
||||||
@@ -454,6 +475,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/in_app_review/ios"
|
:path: ".symlinks/plugins/in_app_review/ios"
|
||||||
irondash_engine_context:
|
irondash_engine_context:
|
||||||
:path: ".symlinks/plugins/irondash_engine_context/ios"
|
:path: ".symlinks/plugins/irondash_engine_context/ios"
|
||||||
|
just_audio:
|
||||||
|
:path: ".symlinks/plugins/just_audio/darwin"
|
||||||
livekit_client:
|
livekit_client:
|
||||||
:path: ".symlinks/plugins/livekit_client/ios"
|
:path: ".symlinks/plugins/livekit_client/ios"
|
||||||
local_auth_darwin:
|
local_auth_darwin:
|
||||||
@@ -476,6 +499,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
|
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
|
||||||
protocol_handler_ios:
|
protocol_handler_ios:
|
||||||
:path: ".symlinks/plugins/protocol_handler_ios/ios"
|
:path: ".symlinks/plugins/protocol_handler_ios/ios"
|
||||||
|
quick_actions_ios:
|
||||||
|
:path: ".symlinks/plugins/quick_actions_ios/ios"
|
||||||
receive_sharing_intent:
|
receive_sharing_intent:
|
||||||
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
||||||
record_ios:
|
record_ios:
|
||||||
@@ -498,11 +523,14 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios"
|
:path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
|
video_thumbnail:
|
||||||
|
:path: ".symlinks/plugins/video_thumbnail/ios"
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Alamofire: bd5e7b23a1a750975288482c1831d71e74415f86
|
Alamofire: bd5e7b23a1a750975288482c1831d71e74415f86
|
||||||
|
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
||||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||||
@@ -525,6 +553,7 @@ SPEC CHECKSUMS:
|
|||||||
FirebaseRemoteConfigInterop: 3443b8cb8fffd76bb3e03b2a84bfd3db952fcda4
|
FirebaseRemoteConfigInterop: 3443b8cb8fffd76bb3e03b2a84bfd3db952fcda4
|
||||||
FirebaseSessions: 2e8f808347e665dff3e5843f275715f07045297d
|
FirebaseSessions: 2e8f808347e665dff3e5843f275715f07045297d
|
||||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||||
|
flutter_app_intents: e77f999f398c841ab584a1925dbce33ee0168fb5
|
||||||
flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9
|
flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9
|
||||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||||
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
||||||
@@ -542,6 +571,7 @@ SPEC CHECKSUMS:
|
|||||||
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
||||||
in_app_review: 7dd1ea365263f834b8464673f9df72c80c17c937
|
in_app_review: 7dd1ea365263f834b8464673f9df72c80c17c937
|
||||||
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
||||||
|
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
|
||||||
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
|
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
|
||||||
Kingfisher: 23d18f54677d973b713e54ce6a8f5eef6e7056ba
|
Kingfisher: 23d18f54677d973b713e54ce6a8f5eef6e7056ba
|
||||||
KingfisherWebP: 38b9721821947f547afb78f933f75f4f9e0ae402
|
KingfisherWebP: 38b9721821947f547afb78f933f75f4f9e0ae402
|
||||||
@@ -561,6 +591,7 @@ SPEC CHECKSUMS:
|
|||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||||
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
||||||
|
quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779
|
||||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||||
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
||||||
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
|
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
|
||||||
@@ -575,9 +606,10 @@ SPEC CHECKSUMS:
|
|||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
|
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
|
||||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||||
|
video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140
|
||||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||||
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
|
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
|
||||||
|
|
||||||
PODFILE CHECKSUM: 585198f58dca90ac6492607c83a8d17045ab3852
|
PODFILE CHECKSUM: 5a3652182a0f0e1093d3ac36dcabc72f6cc46b3a
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
5D8143680678FCD1D1827271 /* Pods_Solian_Watch_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9C046CF867AE03DC170F861 /* Pods_Solian_Watch_App.framework */; };
|
5D8143680678FCD1D1827271 /* Pods_Solian_Watch_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9C046CF867AE03DC170F861 /* Pods_Solian_Watch_App.framework */; };
|
||||||
|
7301DB032F08D99C008390F3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7301DB022F08D99C008390F3 /* WidgetKit.framework */; };
|
||||||
|
7301DB052F08D99C008390F3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7301DB042F08D99C008390F3 /* SwiftUI.framework */; };
|
||||||
|
7301DB102F08D99D008390F3 /* SolianWidgetExtensionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 7301DB012F08D99C008390F3 /* SolianWidgetExtensionExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
7310A7DF2EB10963002C0FD3 /* Solian Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7310A7D42EB10962002C0FD3 /* Solian Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
7310A7DF2EB10963002C0FD3 /* Solian Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7310A7D42EB10962002C0FD3 /* Solian Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
73ACDFAD2E3D0E6100B63535 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */; };
|
73ACDFAD2E3D0E6100B63535 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */; };
|
||||||
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
@@ -36,6 +39,13 @@
|
|||||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||||
remoteInfo = Runner;
|
remoteInfo = Runner;
|
||||||
};
|
};
|
||||||
|
7301DB0E2F08D99D008390F3 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 7301DB002F08D99C008390F3;
|
||||||
|
remoteInfo = SolianWidgetExtensionExtension;
|
||||||
|
};
|
||||||
73ACDFC12E3D0E6100B63535 /* PBXContainerItemProxy */ = {
|
73ACDFC12E3D0E6100B63535 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
@@ -77,6 +87,7 @@
|
|||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 13;
|
dstSubfolderSpec = 13;
|
||||||
files = (
|
files = (
|
||||||
|
7301DB102F08D99D008390F3 /* SolianWidgetExtensionExtension.appex in Embed Foundation Extensions */,
|
||||||
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */,
|
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */,
|
||||||
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */,
|
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */,
|
||||||
73CDD6812DEC00480059D95D /* SolianNotificationService.appex in Embed Foundation Extensions */,
|
73CDD6812DEC00480059D95D /* SolianNotificationService.appex in Embed Foundation Extensions */,
|
||||||
@@ -117,6 +128,10 @@
|
|||||||
39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
3A1C47BD29CC6AC2587D4DBE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
3A1C47BD29CC6AC2587D4DBE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
7301DB012F08D99C008390F3 /* SolianWidgetExtensionExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianWidgetExtensionExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
7301DB022F08D99C008390F3 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||||
|
7301DB042F08D99C008390F3 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||||
|
7301DB162F08D9A5008390F3 /* SolianWidgetExtensionExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SolianWidgetExtensionExtension.entitlements; sourceTree = "<group>"; };
|
||||||
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Solian Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Solian Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
737E920B2DB6A9FF00BE9CDB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
737E920B2DB6A9FF00BE9CDB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -151,6 +166,13 @@
|
|||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
7301DB142F08D99D008390F3 /* Exceptions for "SolianWidgetExtension" folder in "SolianWidgetExtensionExtension" target */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
membershipExceptions = (
|
||||||
|
Info.plist,
|
||||||
|
);
|
||||||
|
target = 7301DB002F08D99C008390F3 /* SolianWidgetExtensionExtension */;
|
||||||
|
};
|
||||||
73ACDFCA2E3D0E6100B63535 /* Exceptions for "SolianBroadcastExtension" folder in "SolianBroadcastExtension" target */ = {
|
73ACDFCA2E3D0E6100B63535 /* Exceptions for "SolianBroadcastExtension" folder in "SolianBroadcastExtension" target */ = {
|
||||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
membershipExceptions = (
|
membershipExceptions = (
|
||||||
@@ -177,12 +199,21 @@
|
|||||||
membershipExceptions = (
|
membershipExceptions = (
|
||||||
CloudFile.swift,
|
CloudFile.swift,
|
||||||
DataExchange.swift,
|
DataExchange.swift,
|
||||||
|
GroupDefaultSync.swift,
|
||||||
);
|
);
|
||||||
target = 73CDD6792DEC00480059D95D /* SolianNotificationService */;
|
target = 73CDD6792DEC00480059D95D /* SolianNotificationService */;
|
||||||
};
|
};
|
||||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
7301DB062F08D99C008390F3 /* SolianWidgetExtension */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
7301DB142F08D99D008390F3 /* Exceptions for "SolianWidgetExtension" folder in "SolianWidgetExtensionExtension" target */,
|
||||||
|
);
|
||||||
|
path = SolianWidgetExtension;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
7310A7D52EB10962002C0FD3 /* Solian Watch App */ = {
|
7310A7D52EB10962002C0FD3 /* Solian Watch App */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
exceptions = (
|
exceptions = (
|
||||||
@@ -233,6 +264,15 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
7301DAFE2F08D99C008390F3 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
7301DB052F08D99C008390F3 /* SwiftUI.framework in Frameworks */,
|
||||||
|
7301DB032F08D99C008390F3 /* WidgetKit.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
7310A7D12EB10962002C0FD3 /* Frameworks */ = {
|
7310A7D12EB10962002C0FD3 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -295,6 +335,8 @@
|
|||||||
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */,
|
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */,
|
||||||
73ACDFB82E3D0E6100B63535 /* UIKit.framework */,
|
73ACDFB82E3D0E6100B63535 /* UIKit.framework */,
|
||||||
C9C046CF867AE03DC170F861 /* Pods_Solian_Watch_App.framework */,
|
C9C046CF867AE03DC170F861 /* Pods_Solian_Watch_App.framework */,
|
||||||
|
7301DB022F08D99C008390F3 /* WidgetKit.framework */,
|
||||||
|
7301DB042F08D99C008390F3 /* SwiftUI.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -341,12 +383,14 @@
|
|||||||
97C146E51CF9000F007C117D = {
|
97C146E51CF9000F007C117D = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
7301DB162F08D9A5008390F3 /* SolianWidgetExtensionExtension.entitlements */,
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
|
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
|
||||||
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
|
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
|
||||||
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||||
7310A7D52EB10962002C0FD3 /* Solian Watch App */,
|
7310A7D52EB10962002C0FD3 /* Solian Watch App */,
|
||||||
|
7301DB062F08D99C008390F3 /* SolianWidgetExtension */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
91E124CE95BCB4DCD890160D /* Pods */,
|
91E124CE95BCB4DCD890160D /* Pods */,
|
||||||
@@ -364,6 +408,7 @@
|
|||||||
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
|
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
|
||||||
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
|
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
|
||||||
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */,
|
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */,
|
||||||
|
7301DB012F08D99C008390F3 /* SolianWidgetExtensionExtension.appex */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -408,6 +453,26 @@
|
|||||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||||
productType = "com.apple.product-type.bundle.unit-test";
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
};
|
};
|
||||||
|
7301DB002F08D99C008390F3 /* SolianWidgetExtensionExtension */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 7301DB152F08D99D008390F3 /* Build configuration list for PBXNativeTarget "SolianWidgetExtensionExtension" */;
|
||||||
|
buildPhases = (
|
||||||
|
7301DAFD2F08D99C008390F3 /* Sources */,
|
||||||
|
7301DAFE2F08D99C008390F3 /* Frameworks */,
|
||||||
|
7301DAFF2F08D99C008390F3 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
7301DB062F08D99C008390F3 /* SolianWidgetExtension */,
|
||||||
|
);
|
||||||
|
name = SolianWidgetExtensionExtension;
|
||||||
|
productName = SolianWidgetExtensionExtension;
|
||||||
|
productReference = 7301DB012F08D99C008390F3 /* SolianWidgetExtensionExtension.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
7310A7D32EB10962002C0FD3 /* Solian Watch App */ = {
|
7310A7D32EB10962002C0FD3 /* Solian Watch App */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "Solian Watch App" */;
|
buildConfigurationList = 7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "Solian Watch App" */;
|
||||||
@@ -515,6 +580,7 @@
|
|||||||
73CDD6802DEC00480059D95D /* PBXTargetDependency */,
|
73CDD6802DEC00480059D95D /* PBXTargetDependency */,
|
||||||
73C305D72E0BE878009035B9 /* PBXTargetDependency */,
|
73C305D72E0BE878009035B9 /* PBXTargetDependency */,
|
||||||
73ACDFC22E3D0E6100B63535 /* PBXTargetDependency */,
|
73ACDFC22E3D0E6100B63535 /* PBXTargetDependency */,
|
||||||
|
7301DB0F2F08D99D008390F3 /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
fileSystemSynchronizedGroups = (
|
fileSystemSynchronizedGroups = (
|
||||||
73268D272DEB012A0076E970 /* Services */,
|
73268D272DEB012A0076E970 /* Services */,
|
||||||
@@ -531,7 +597,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastSwiftUpdateCheck = 2600;
|
LastSwiftUpdateCheck = 2620;
|
||||||
LastUpgradeCheck = 1510;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
@@ -539,6 +605,9 @@
|
|||||||
CreatedOnToolsVersion = 14.0;
|
CreatedOnToolsVersion = 14.0;
|
||||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||||
};
|
};
|
||||||
|
7301DB002F08D99C008390F3 = {
|
||||||
|
CreatedOnToolsVersion = 26.2;
|
||||||
|
};
|
||||||
7310A7D32EB10962002C0FD3 = {
|
7310A7D32EB10962002C0FD3 = {
|
||||||
CreatedOnToolsVersion = 26.0.1;
|
CreatedOnToolsVersion = 26.0.1;
|
||||||
};
|
};
|
||||||
@@ -563,6 +632,11 @@
|
|||||||
knownRegions = (
|
knownRegions = (
|
||||||
en,
|
en,
|
||||||
Base,
|
Base,
|
||||||
|
"zh-Hans",
|
||||||
|
es,
|
||||||
|
ja,
|
||||||
|
ko,
|
||||||
|
"zh-Hant",
|
||||||
);
|
);
|
||||||
mainGroup = 97C146E51CF9000F007C117D;
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
@@ -576,6 +650,7 @@
|
|||||||
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
|
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
|
||||||
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||||
7310A7D32EB10962002C0FD3 /* Solian Watch App */,
|
7310A7D32EB10962002C0FD3 /* Solian Watch App */,
|
||||||
|
7301DB002F08D99C008390F3 /* SolianWidgetExtensionExtension */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -588,6 +663,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
7301DAFF2F08D99C008390F3 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
7310A7D22EB10962002C0FD3 /* Resources */ = {
|
7310A7D22EB10962002C0FD3 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -852,6 +934,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
7301DAFD2F08D99C008390F3 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
7310A7D02EB10962002C0FD3 /* Sources */ = {
|
7310A7D02EB10962002C0FD3 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -898,6 +987,11 @@
|
|||||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
7301DB0F2F08D99D008390F3 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 7301DB002F08D99C008390F3 /* SolianWidgetExtensionExtension */;
|
||||||
|
targetProxy = 7301DB0E2F08D99D008390F3 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
73ACDFC22E3D0E6100B63535 /* PBXTargetDependency */ = {
|
73ACDFC22E3D0E6100B63535 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = 73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */;
|
target = 73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */;
|
||||||
@@ -1002,7 +1096,7 @@
|
|||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1080,6 +1174,138 @@
|
|||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
};
|
};
|
||||||
|
7301DB112F08D99D008390F3 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = SolianWidgetExtensionExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = SolianWidgetExtension/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = SolianWidgetExtension;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianWidgetExtension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
7301DB122F08D99D008390F3 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = SolianWidgetExtensionExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = SolianWidgetExtension/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = SolianWidgetExtension;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianWidgetExtension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
7301DB132F08D99D008390F3 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = SolianWidgetExtensionExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = SolianWidgetExtension/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = SolianWidgetExtension;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianWidgetExtension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
7310A7E02EB10963002C0FD3 /* Debug */ = {
|
7310A7E02EB10963002C0FD3 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 31EA49B10397BD4145AD765E /* Pods-Solian Watch App.debug.xcconfig */;
|
baseConfigurationReference = 31EA49B10397BD4145AD765E /* Pods-Solian Watch App.debug.xcconfig */;
|
||||||
@@ -1371,7 +1597,7 @@
|
|||||||
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1416,7 +1642,7 @@
|
|||||||
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1458,7 +1684,7 @@
|
|||||||
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1724,7 +1950,7 @@
|
|||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1755,7 +1981,7 @@
|
|||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1785,6 +2011,16 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
7301DB152F08D99D008390F3 /* Build configuration list for PBXNativeTarget "SolianWidgetExtensionExtension" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
7301DB112F08D99D008390F3 /* Debug */,
|
||||||
|
7301DB122F08D99D008390F3 /* Release */,
|
||||||
|
7301DB132F08D99D008390F3 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "Solian Watch App" */ = {
|
7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "Solian Watch App" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "7310A7D32EB10962002C0FD3"
|
||||||
|
BuildableName = "Solian Watch App.app"
|
||||||
|
BlueprintName = "Solian Watch App"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "7310A7D32EB10962002C0FD3"
|
||||||
|
BuildableName = "Solian Watch App.app"
|
||||||
|
BlueprintName = "Solian Watch App"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "7310A7D32EB10962002C0FD3"
|
||||||
|
BuildableName = "Solian Watch App.app"
|
||||||
|
BlueprintName = "Solian Watch App"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "73ACDFAA2E3D0E6100B63535"
|
||||||
|
BuildableName = "SolianBroadcastExtension.appex"
|
||||||
|
BlueprintName = "SolianBroadcastExtension"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "73CDD6792DEC00480059D95D"
|
||||||
|
BuildableName = "SolianNotificationService.appex"
|
||||||
|
BlueprintName = "SolianNotificationService"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "73C305CD2E0BE878009035B9"
|
||||||
|
BuildableName = "SolianShareExtension.appex"
|
||||||
|
BlueprintName = "SolianShareExtension"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "7301DB002F08D99C008390F3"
|
||||||
|
BuildableName = "SolianWidgetExtensionExtension.appex"
|
||||||
|
BlueprintName = "SolianWidgetExtensionExtension"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "7310A7D32EB10962002C0FD3"
|
||||||
|
BuildableName = "Solian Watch App.app"
|
||||||
|
BlueprintName = "Solian Watch App"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "_XCWidgetKind"
|
||||||
|
value = ""
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "_XCWidgetDefaultView"
|
||||||
|
value = "timeline"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "_XCWidgetFamily"
|
||||||
|
value = "systemMedium"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
|
import WidgetKit
|
||||||
import UIKit
|
import UIKit
|
||||||
import WatchConnectivity
|
import WatchConnectivity
|
||||||
|
import AppIntents
|
||||||
|
import flutter_app_intents
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
@@ -11,6 +14,9 @@ import WatchConnectivity
|
|||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
|
syncDefaultsToGroup()
|
||||||
|
WidgetCenter.shared.reloadAllTimelines()
|
||||||
|
|
||||||
UNUserNotificationCenter.current().delegate = notifyDelegate
|
UNUserNotificationCenter.current().delegate = notifyDelegate
|
||||||
|
|
||||||
let replyableMessageCategory = UNNotificationCategory(
|
let replyableMessageCategory = UNNotificationCategory(
|
||||||
@@ -29,6 +35,9 @@ import WatchConnectivity
|
|||||||
|
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
|
||||||
|
// Setup widget sync method channel
|
||||||
|
setupWidgetSyncChannel()
|
||||||
|
|
||||||
// Always initialize and retain a strong reference
|
// Always initialize and retain a strong reference
|
||||||
if WCSession.isSupported() {
|
if WCSession.isSupported() {
|
||||||
AppDelegate.sharedWatchConnectivityService = WatchConnectivityService.shared
|
AppDelegate.sharedWatchConnectivityService = WatchConnectivityService.shared
|
||||||
@@ -38,6 +47,30 @@ import WatchConnectivity
|
|||||||
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func setupWidgetSyncChannel() {
|
||||||
|
let controller = window?.rootViewController as? FlutterViewController
|
||||||
|
let channel = FlutterMethodChannel(name: "dev.solsynth.solian/widget", binaryMessenger: controller!.binaryMessenger)
|
||||||
|
|
||||||
|
channel.setMethodCallHandler { [weak self] (call, result) in
|
||||||
|
if call.method == "syncToWidget" {
|
||||||
|
syncDefaultsToGroup()
|
||||||
|
WidgetCenter.shared.reloadAllTimelines()
|
||||||
|
result(true)
|
||||||
|
} else {
|
||||||
|
result(FlutterMethodNotImplemented)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func applicationDidEnterBackground(_ application: UIApplication) {
|
||||||
|
syncDefaultsToGroup()
|
||||||
|
WidgetCenter.shared.reloadAllTimelines()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func applicationWillTerminate(_ application: UIApplication) {
|
||||||
|
syncDefaultsToGroup()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
||||||
@@ -76,7 +109,7 @@ final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
|||||||
let token = UserDefaults.standard.getFlutterToken()
|
let token = UserDefaults.standard.getFlutterToken()
|
||||||
let serverUrl = UserDefaults.standard.getServerUrl()
|
let serverUrl = UserDefaults.standard.getServerUrl()
|
||||||
|
|
||||||
var data: [String: Any] = ["serverUrl": serverUrl ?? ""]
|
var data: [String: Any] = ["serverUrl": serverUrl]
|
||||||
if let token = token {
|
if let token = token {
|
||||||
data["token"] = token
|
data["token"] = token
|
||||||
}
|
}
|
||||||
@@ -94,7 +127,7 @@ final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
|||||||
let token = UserDefaults.standard.getFlutterToken()
|
let token = UserDefaults.standard.getFlutterToken()
|
||||||
let serverUrl = UserDefaults.standard.getServerUrl()
|
let serverUrl = UserDefaults.standard.getServerUrl()
|
||||||
|
|
||||||
var data: [String: Any] = ["serverUrl": serverUrl ?? ""]
|
var data: [String: Any] = ["serverUrl": serverUrl]
|
||||||
if let token = token {
|
if let token = token {
|
||||||
data["token"] = token
|
data["token"] = token
|
||||||
}
|
}
|
||||||
@@ -107,3 +140,412 @@ final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - App Intents
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct OpenChatIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Open Chat"
|
||||||
|
static var description = IntentDescription("Open a specific chat room")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
@Parameter(title: "Channel ID")
|
||||||
|
var channelId: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "open_chat",
|
||||||
|
parameters: ["channelId": channelId ?? ""]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Chat opened"
|
||||||
|
return .result(value: value)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to open chat"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct OpenPostIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Open Post"
|
||||||
|
static var description = IntentDescription("Open a specific post")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
@Parameter(title: "Post ID")
|
||||||
|
var postId: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "open_post",
|
||||||
|
parameters: ["postId": postId ?? ""]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Post opened"
|
||||||
|
return .result(value: value)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to open post"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct OpenComposeIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Open Compose"
|
||||||
|
static var description = IntentDescription("Open compose post screen")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "open_compose",
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Compose screen opened"
|
||||||
|
return .result(value: value)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to open compose"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct ComposePostIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Compose Post"
|
||||||
|
static var description = IntentDescription("Create a new post")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "compose_post",
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Compose screen opened"
|
||||||
|
return .result(value: value)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to compose post"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct SearchContentIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Search Content"
|
||||||
|
static var description = IntentDescription("Search for content")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
@Parameter(title: "Search Query")
|
||||||
|
var query: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "search_content",
|
||||||
|
parameters: ["query": query ?? ""]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Search opened"
|
||||||
|
return .result(value: value)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to search"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct ViewNotificationsIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "View Notifications"
|
||||||
|
static var description = IntentDescription("View notifications")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "view_notifications",
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Notifications opened"
|
||||||
|
return .result(value: value)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to view notifications"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct CheckNotificationsIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Check Notifications"
|
||||||
|
static var description = IntentDescription("Check notification count")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "check_notifications",
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "You have new notifications"
|
||||||
|
return .result(
|
||||||
|
value: value,
|
||||||
|
dialog: "\(value)"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to check notifications"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct SendMessageIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Send Message"
|
||||||
|
static var description = IntentDescription("Send a message to a chat channel")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
@Parameter(title: "Channel ID")
|
||||||
|
var channelId: String?
|
||||||
|
|
||||||
|
@Parameter(title: "Message Content")
|
||||||
|
var content: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
||||||
|
guard let channelId = channelId, !channelId.isEmpty else {
|
||||||
|
throw AppIntentError.executionFailed("Channel ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let content = content, !content.isEmpty else {
|
||||||
|
throw AppIntentError.executionFailed("Message content is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "send_message",
|
||||||
|
parameters: ["channelId": channelId, "content": content]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Message sent"
|
||||||
|
return .result(
|
||||||
|
value: value,
|
||||||
|
dialog: "\(value)"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to send message"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct ReadMessagesIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Read Messages"
|
||||||
|
static var description = IntentDescription("Read recent messages from a chat channel")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
@Parameter(title: "Channel ID")
|
||||||
|
var channelId: String?
|
||||||
|
|
||||||
|
@Parameter(title: "Number of Messages", default: "5")
|
||||||
|
var limit: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
||||||
|
guard let channelId = channelId, !channelId.isEmpty else {
|
||||||
|
throw AppIntentError.executionFailed("Channel ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
let limit = limit ?? "5"
|
||||||
|
var parameters: [String: Any] = ["channelId": channelId]
|
||||||
|
parameters["limit"] = limit
|
||||||
|
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "read_messages",
|
||||||
|
parameters: parameters
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Messages retrieved"
|
||||||
|
return .result(
|
||||||
|
value: value,
|
||||||
|
dialog: "\(value)"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to read messages"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct CheckUnreadChatsIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Check Unread Chats"
|
||||||
|
static var description = IntentDescription("Check number of unread chat messages")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "check_unread_chats",
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "No unread messages"
|
||||||
|
return .result(
|
||||||
|
value: value,
|
||||||
|
dialog: "\(value)"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to check unread chats"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct MarkNotificationsReadIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "Mark Notifications Read"
|
||||||
|
static var description = IntentDescription("Mark all notifications as read")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
||||||
|
let plugin = FlutterAppIntentsPlugin.shared
|
||||||
|
let result = await plugin.handleIntentInvocation(
|
||||||
|
identifier: "mark_notifications_read",
|
||||||
|
parameters: [:]
|
||||||
|
)
|
||||||
|
|
||||||
|
if let success = result["success"] as? Bool, success {
|
||||||
|
let value = result["value"] as? String ?? "Notifications marked as read"
|
||||||
|
return .result(
|
||||||
|
value: value,
|
||||||
|
dialog: "\(value)"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let errorMessage = result["error"] as? String ?? "Failed to mark notifications as read"
|
||||||
|
throw AppIntentError.executionFailed(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AppIntentError: Error {
|
||||||
|
case executionFailed(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct AppShortcuts: AppShortcutsProvider {
|
||||||
|
static var appShortcuts: [AppShortcut] {
|
||||||
|
return [
|
||||||
|
// Open chat
|
||||||
|
AppShortcut(
|
||||||
|
intent: OpenChatIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Open chat with \(.applicationName)",
|
||||||
|
"Go to chat using \(.applicationName)",
|
||||||
|
"Show chat in \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Open post
|
||||||
|
AppShortcut(
|
||||||
|
intent: OpenPostIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Open post with \(.applicationName)",
|
||||||
|
"Show post using \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Compose
|
||||||
|
AppShortcut(
|
||||||
|
intent: OpenComposeIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Open compose with \(.applicationName)",
|
||||||
|
"New post using \(.applicationName)",
|
||||||
|
"Write post in \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Search
|
||||||
|
AppShortcut(
|
||||||
|
intent: SearchContentIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Search in \(.applicationName)",
|
||||||
|
"Find content using \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Check notifications
|
||||||
|
AppShortcut(
|
||||||
|
intent: CheckNotificationsIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Check notifications with \(.applicationName)",
|
||||||
|
"Get notifications using \(.applicationName)",
|
||||||
|
"Do I have notifications in \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Send message
|
||||||
|
AppShortcut(
|
||||||
|
intent: SendMessageIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Send message with \(.applicationName)",
|
||||||
|
"Post message using \(.applicationName)",
|
||||||
|
"Send text using \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Read messages
|
||||||
|
AppShortcut(
|
||||||
|
intent: ReadMessagesIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Read messages with \(.applicationName)",
|
||||||
|
"Get chat using \(.applicationName)",
|
||||||
|
"Show messages with \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Check unread chats
|
||||||
|
AppShortcut(
|
||||||
|
intent: CheckUnreadChatsIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Check unread chats with \(.applicationName)",
|
||||||
|
"Do I have messages using \(.applicationName)",
|
||||||
|
"Get unread messages with \(.applicationName)"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
// Mark notifications read
|
||||||
|
AppShortcut(
|
||||||
|
intent: MarkNotificationsReadIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Mark notifications read with \(.applicationName)",
|
||||||
|
"Clear notifications using \(.applicationName)",
|
||||||
|
"Mark all read with \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
6
ios/Runner/Assets.xcassets/Contents.json
Normal file
6
ios/Runner/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,6 +63,18 @@
|
|||||||
<string>Allow the Solar Network verify your ownership of the logged in account and continue your action quickly.</string>
|
<string>Allow the Solar Network verify your ownership of the logged in account and continue your action quickly.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
||||||
|
<key>NSSpeechRecognitionUsageDescription</key>
|
||||||
|
<string>Solian uses speech recognition for Siri integration</string>
|
||||||
|
<key>NSAppIntentsConfiguration</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAppIntentsPackage</key>
|
||||||
|
<string>dev.solsynth.solian</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSAppIntentsMetadata</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAppIntentsSupported</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class NotifyDelegate: UIResponder, UNUserNotificationCenterDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let serverUrl = UserDefaults.standard.getServerUrl()
|
let serverUrl = UserDefaults.standard.getServerUrl()
|
||||||
let url = "\(serverUrl)/sphere/chat/\(metadata["room_id"] ?? "")/messages"
|
let url = "\(serverUrl)/messager/chat/\(metadata["room_id"] ?? "")/messages"
|
||||||
|
|
||||||
let parameters: [String: Any?] = [
|
let parameters: [String: Any?] = [
|
||||||
"content": textResponse.userText,
|
"content": textResponse.userText,
|
||||||
|
|||||||
41
ios/Runner/Services/GroupDefaultSync.swift
Normal file
41
ios/Runner/Services/GroupDefaultSync.swift
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// GroupDefaultSync.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/3.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
private let flutterKeyPrefix = "flutter."
|
||||||
|
|
||||||
|
private let flutterKeysToSync: [String] = [
|
||||||
|
"dyn_user_tk",
|
||||||
|
"app_server_url"
|
||||||
|
]
|
||||||
|
|
||||||
|
func syncDefaultsToGroup() {
|
||||||
|
print("[iOS] syncDefaultsToGroup() called")
|
||||||
|
|
||||||
|
let standard = UserDefaults.standard
|
||||||
|
let shared = UserDefaults(suiteName: "group.solsynth.solian")
|
||||||
|
|
||||||
|
guard let shared else {
|
||||||
|
print("[iOS] App Group UserDefaults not available")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for key in flutterKeysToSync {
|
||||||
|
let prefixedKey = key.starts(with: flutterKeyPrefix) ? key : flutterKeyPrefix + key
|
||||||
|
|
||||||
|
if let value = standard.object(forKey: prefixedKey) {
|
||||||
|
print("[iOS] Syncing key to App Group: \(prefixedKey)")
|
||||||
|
shared.set(value, forKey: prefixedKey)
|
||||||
|
} else {
|
||||||
|
print("[iOS] Key \(prefixedKey) was not found in the app data, skipping...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shared.synchronize()
|
||||||
|
print("[iOS] Sync completed")
|
||||||
|
}
|
||||||
@@ -261,7 +261,7 @@ class NetworkService {
|
|||||||
guard let baseURL = URL(string: serverUrl) else {
|
guard let baseURL = URL(string: serverUrl) else {
|
||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
let url = baseURL.appendingPathComponent("/sphere/chat")
|
let url = baseURL.appendingPathComponent("/messager/chat")
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.httpMethod = "GET"
|
request.httpMethod = "GET"
|
||||||
@@ -283,7 +283,7 @@ class NetworkService {
|
|||||||
guard let baseURL = URL(string: serverUrl) else {
|
guard let baseURL = URL(string: serverUrl) else {
|
||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
let url = baseURL.appendingPathComponent("/sphere/chat/\(identifier)")
|
let url = baseURL.appendingPathComponent("/messager/chat/\(identifier)")
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.httpMethod = "GET"
|
request.httpMethod = "GET"
|
||||||
@@ -308,7 +308,7 @@ class NetworkService {
|
|||||||
guard let baseURL = URL(string: serverUrl) else {
|
guard let baseURL = URL(string: serverUrl) else {
|
||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
let url = baseURL.appendingPathComponent("/sphere/chat/invites")
|
let url = baseURL.appendingPathComponent("/messager/chat/invites")
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.httpMethod = "GET"
|
request.httpMethod = "GET"
|
||||||
@@ -330,7 +330,7 @@ class NetworkService {
|
|||||||
guard let baseURL = URL(string: serverUrl) else {
|
guard let baseURL = URL(string: serverUrl) else {
|
||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/accept")
|
let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/accept")
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.httpMethod = "POST"
|
request.httpMethod = "POST"
|
||||||
@@ -351,7 +351,7 @@ class NetworkService {
|
|||||||
guard let baseURL = URL(string: serverUrl) else {
|
guard let baseURL = URL(string: serverUrl) else {
|
||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/decline")
|
let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/decline")
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.httpMethod = "POST"
|
request.httpMethod = "POST"
|
||||||
@@ -375,9 +375,9 @@ class NetworkService {
|
|||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try a different pattern: /sphere/chat/messages with roomId as query param
|
// Try a different pattern: /messager/chat/messages with roomId as query param
|
||||||
var components = URLComponents(
|
var components = URLComponents(
|
||||||
url: baseURL.appendingPathComponent("/sphere/chat/\(chatRoomId)/messages"),
|
url: baseURL.appendingPathComponent("/messager/chat/\(chatRoomId)/messages"),
|
||||||
resolvingAgainstBaseURL: false
|
resolvingAgainstBaseURL: false
|
||||||
)!
|
)!
|
||||||
var queryItems = [
|
var queryItems = [
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ struct ChatRoomView: View {
|
|||||||
]
|
]
|
||||||
|
|
||||||
// Create the URL
|
// Create the URL
|
||||||
guard let url = URL(string: "\(serverUrl)/sphere/chat/\(room.id)/messages") else {
|
guard let url = URL(string: "\(serverUrl)/messager/chat/\(room.id)/messages") else {
|
||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
// Created by LittleSheep on 2025/5/31.
|
// Created by LittleSheep on 2025/5/31.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UserNotifications
|
@preconcurrency import UserNotifications
|
||||||
import Intents
|
import Intents
|
||||||
import Kingfisher
|
import Kingfisher
|
||||||
import UniformTypeIdentifiers
|
import UniformTypeIdentifiers
|
||||||
@@ -53,8 +53,10 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
private func processNotification(request: UNNotificationRequest, content: UNMutableNotificationContent) throws {
|
private func processNotification(request: UNNotificationRequest, content: UNMutableNotificationContent) throws {
|
||||||
switch content.userInfo["type"] as? String {
|
switch content.userInfo["type"] as? String {
|
||||||
case "messages.new":
|
case "messages.new":
|
||||||
|
content.sound = UNNotificationSound(named: UNNotificationSoundName("SfxMessage.caf"))
|
||||||
try handleMessagingNotification(request: request, content: content)
|
try handleMessagingNotification(request: request, content: content)
|
||||||
default:
|
default:
|
||||||
|
content.sound = UNNotificationSound(named: UNNotificationSoundName("SfxNotification.caf"))
|
||||||
try handleDefaultNotification(content: content)
|
try handleDefaultNotification(content: content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +151,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
|
|
||||||
let dispatchGroup = DispatchGroup()
|
let dispatchGroup = DispatchGroup()
|
||||||
var attachments: [UNNotificationAttachment] = []
|
var attachments: [UNNotificationAttachment] = []
|
||||||
let lock = NSLock() // To synchronize access to the attachments array
|
let queue = DispatchQueue(label: "dev.solsynth.solian.nse")
|
||||||
|
|
||||||
for attachmentUrl in attachmentUrls {
|
for attachmentUrl in attachmentUrls {
|
||||||
guard let remoteUrl = URL(string: attachmentUrl) else {
|
guard let remoteUrl = URL(string: attachmentUrl) else {
|
||||||
@@ -163,7 +165,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
.processor(scaleProcessor)
|
.processor(scaleProcessor)
|
||||||
] : nil) { [weak self] result in
|
] : nil) { [weak self] result in
|
||||||
defer { dispatchGroup.leave() }
|
defer { dispatchGroup.leave() }
|
||||||
guard let self = self else { return }
|
guard self != nil else { return }
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let retrievalResult):
|
case .success(let retrievalResult):
|
||||||
@@ -176,12 +178,12 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
try retrievalResult.image.pngData()?.write(to: cachedFileUrl)
|
try retrievalResult.image.pngData()?.write(to: cachedFileUrl)
|
||||||
|
|
||||||
if let attachment = try? UNNotificationAttachment(identifier: attachmentUrl, url: cachedFileUrl, options: [
|
if let attachment = try? UNNotificationAttachment(identifier: attachmentUrl, url: cachedFileUrl, options: [
|
||||||
UNNotificationAttachmentOptionsTypeHintKey: type?.identifier as Any,
|
UNNotificationAttachmentOptionsTypeHintKey: UTType.png.identifier,
|
||||||
UNNotificationAttachmentOptionsThumbnailHiddenKey: 0,
|
UNNotificationAttachmentOptionsThumbnailHiddenKey: 0,
|
||||||
]) {
|
]) {
|
||||||
lock.lock()
|
queue.async {
|
||||||
attachments.append(attachment)
|
attachments.append(attachment)
|
||||||
lock.unlock()
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
print("Failed to write media to temporary file: \(error.localizedDescription)")
|
print("Failed to write media to temporary file: \(error.localizedDescription)")
|
||||||
|
|||||||
BIN
ios/SolianNotificationService/SfxMessage.caf
Normal file
BIN
ios/SolianNotificationService/SfxMessage.caf
Normal file
Binary file not shown.
BIN
ios/SolianNotificationService/SfxNotification.caf
Normal file
BIN
ios/SolianNotificationService/SfxNotification.caf
Normal file
Binary file not shown.
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "icon.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "icon-dark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filename" : "icon 1.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
21
ios/SolianWidgetExtension/Assets.xcassets/CloudyLamb.imageset/Contents.json
vendored
Normal file
21
ios/SolianWidgetExtension/Assets.xcassets/CloudyLamb.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "icon.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
ios/SolianWidgetExtension/Assets.xcassets/CloudyLamb.imageset/icon.png
vendored
Normal file
BIN
ios/SolianWidgetExtension/Assets.xcassets/CloudyLamb.imageset/icon.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
21
ios/SolianWidgetExtension/Assets.xcassets/CloudyLambDark.imageset/Contents.json
vendored
Normal file
21
ios/SolianWidgetExtension/Assets.xcassets/CloudyLambDark.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "icon-dark.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
ios/SolianWidgetExtension/Assets.xcassets/CloudyLambDark.imageset/icon-dark.png
vendored
Normal file
BIN
ios/SolianWidgetExtension/Assets.xcassets/CloudyLambDark.imageset/icon-dark.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
6
ios/SolianWidgetExtension/Assets.xcassets/Contents.json
Normal file
6
ios/SolianWidgetExtension/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
11
ios/SolianWidgetExtension/Info.plist
Normal file
11
ios/SolianWidgetExtension/Info.plist
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.widgetkit-extension</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
720
ios/SolianWidgetExtension/SolianCheckInWidget.swift
Normal file
720
ios/SolianWidgetExtension/SolianCheckInWidget.swift
Normal file
@@ -0,0 +1,720 @@
|
|||||||
|
//
|
||||||
|
// SolianWidgetExtension.swift
|
||||||
|
// SolianWidgetExtension
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/3.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct CheckInTip: Codable {
|
||||||
|
let isPositive: Bool
|
||||||
|
let title: String
|
||||||
|
let content: String
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case isPositive = "is_positive"
|
||||||
|
case title
|
||||||
|
case content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckInAccount: Codable {
|
||||||
|
let id: String
|
||||||
|
let nick: String?
|
||||||
|
let profile: CheckInProfile?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckInProfile: Codable {
|
||||||
|
let picture: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckInResult: Codable {
|
||||||
|
let id: String
|
||||||
|
let level: Int
|
||||||
|
let rewardPoints: Int
|
||||||
|
let rewardExperience: Int
|
||||||
|
let tips: [CheckInTip]
|
||||||
|
let accountId: String
|
||||||
|
let account: CheckInAccount?
|
||||||
|
let createdAt: String
|
||||||
|
let updatedAt: String
|
||||||
|
let deletedAt: String?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case level
|
||||||
|
case rewardPoints = "reward_points"
|
||||||
|
case rewardExperience = "reward_experience"
|
||||||
|
case tips
|
||||||
|
case accountId = "account_id"
|
||||||
|
case account
|
||||||
|
case createdAt = "created_at"
|
||||||
|
case updatedAt = "updated_at"
|
||||||
|
case deletedAt = "deleted_at"
|
||||||
|
}
|
||||||
|
|
||||||
|
var createdDate: Date? {
|
||||||
|
let formatter = ISO8601DateFormatter()
|
||||||
|
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||||
|
|
||||||
|
if let date = formatter.date(from: createdAt) {
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for timestamps without fractional seconds
|
||||||
|
formatter.formatOptions = [.withInternetDateTime]
|
||||||
|
return formatter.date(from: createdAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotableDay: Codable {
|
||||||
|
let date: String
|
||||||
|
let localName: String
|
||||||
|
let globalName: String
|
||||||
|
let countryCode: String?
|
||||||
|
let localizableKey: String?
|
||||||
|
let holidays: [Int]?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case date
|
||||||
|
case localName = "local_name"
|
||||||
|
case globalName = "global_name"
|
||||||
|
case countryCode = "country_code"
|
||||||
|
case localizableKey = "localizable_key"
|
||||||
|
case holidays
|
||||||
|
}
|
||||||
|
|
||||||
|
var notableDate: Date? {
|
||||||
|
ISO8601DateFormatter().date(from: date)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isToday: Bool {
|
||||||
|
guard let notableDate = notableDate else { return false }
|
||||||
|
let calendar = Calendar.current
|
||||||
|
return calendar.isDateInToday(notableDate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckInService {
|
||||||
|
private let networkService = WidgetNetworkService()
|
||||||
|
|
||||||
|
func fetchCheckInResult() async throws -> CheckInResult? {
|
||||||
|
return try await networkService.makeRequest(path: "/pass/accounts/me/check-in")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotableDayService {
|
||||||
|
private let networkService = WidgetNetworkService()
|
||||||
|
|
||||||
|
func fetchRecentNotableDay() async throws -> NotableDay? {
|
||||||
|
print("[WidgetKit] [NotableDayService] Fetching recent notable day...")
|
||||||
|
do {
|
||||||
|
let result: [NotableDay]? = try await networkService.makeRequest(path: "/pass/notable/me/recent")
|
||||||
|
print("[WidgetKit] [NotableDayService] Result: \(String(describing: result))")
|
||||||
|
|
||||||
|
guard let result = result else {
|
||||||
|
print("[WidgetKit] [NotableDayService] Result is nil")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[WidgetKit] [NotableDayService] Result count: \(result.count)")
|
||||||
|
|
||||||
|
guard result.isEmpty == false else {
|
||||||
|
print("[WidgetKit] [NotableDayService] No notable days found")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let firstDay = result.first!
|
||||||
|
print("[WidgetKit] [NotableDayService] First notable day: \(firstDay.localName), date: \(firstDay.date)")
|
||||||
|
|
||||||
|
return firstDay
|
||||||
|
} catch let decodingError as DecodingError {
|
||||||
|
print("[WidgetKit] [NotableDayService] Decoding error, trying as single object...")
|
||||||
|
print("[WidgetKit] [NotableDayService] Error: \(decodingError.localizedDescription)")
|
||||||
|
|
||||||
|
switch decodingError {
|
||||||
|
case .typeMismatch(let type, let context):
|
||||||
|
print("[WidgetKit] [NotableDayService] Type mismatch: expected \(type), context: \(context.debugDescription)")
|
||||||
|
case .valueNotFound(let type, let context):
|
||||||
|
print("[WidgetKit] [NotableDayService] Value not found: type \(type), context: \(context.debugDescription)")
|
||||||
|
case .keyNotFound(let key, let context):
|
||||||
|
print("[WidgetKit] [NotableDayService] Key not found: \(key), context: \(context.debugDescription)")
|
||||||
|
case .dataCorrupted(let context):
|
||||||
|
print("[WidgetKit] [NotableDayService] Data corrupted: \(context.debugDescription)")
|
||||||
|
@unknown default:
|
||||||
|
print("[WidgetKit] [NotableDayService] Unknown decoding error")
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let singleResult: NotableDay? = try await networkService.makeRequest(path: "/pass/notable/me/recent")
|
||||||
|
print("[WidgetKit] [NotableDayService] Single object decode succeeded: \(singleResult?.localName ?? "nil")")
|
||||||
|
return singleResult
|
||||||
|
} catch {
|
||||||
|
print("[WidgetKit] [NotableDayService] Single object decode also failed: \(error.localizedDescription)")
|
||||||
|
throw decodingError
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("[WidgetKit] [NotableDayService] Error fetching notable day: \(error.localizedDescription)")
|
||||||
|
print("[WidgetKit] [NotableDayService] Error type: \(type(of: error))")
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckInEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let result: CheckInResult?
|
||||||
|
let notableDay: NotableDay?
|
||||||
|
let error: String?
|
||||||
|
let isLoading: Bool
|
||||||
|
|
||||||
|
static func placeholder() -> CheckInEntry {
|
||||||
|
CheckInEntry(date: Date(), result: nil, notableDay: nil, error: nil, isLoading: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Provider: TimelineProvider {
|
||||||
|
private let apiService = CheckInService()
|
||||||
|
|
||||||
|
func placeholder(in context: Context) -> CheckInEntry {
|
||||||
|
CheckInEntry.placeholder()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(in context: Context, completion: @escaping (CheckInEntry) -> ()) {
|
||||||
|
Task {
|
||||||
|
print("[WidgetKit] [Provider] Getting snapshot...")
|
||||||
|
async let checkInResult = try? await apiService.fetchCheckInResult()
|
||||||
|
async let notableDay = try? await NotableDayService().fetchRecentNotableDay()
|
||||||
|
|
||||||
|
let result = try? await checkInResult
|
||||||
|
let day = try? await notableDay
|
||||||
|
|
||||||
|
print("[WidgetKit] [Provider] Snapshot - CheckIn: \(result != nil ? "Found" : "Not found"), NotableDay: \(day != nil ? "Found" : "Not found")")
|
||||||
|
|
||||||
|
let entry = CheckInEntry(date: Date(), result: result, notableDay: day, error: nil, isLoading: false)
|
||||||
|
completion(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
Task {
|
||||||
|
let currentDate = Date()
|
||||||
|
print("[WidgetKit] [Provider] Getting timeline at \(currentDate)...")
|
||||||
|
|
||||||
|
do {
|
||||||
|
async let checkInResult = try await apiService.fetchCheckInResult()
|
||||||
|
async let notableDay = try await NotableDayService().fetchRecentNotableDay()
|
||||||
|
|
||||||
|
let result = try await checkInResult
|
||||||
|
let day = try await notableDay
|
||||||
|
|
||||||
|
print("[WidgetKit] [Provider] Timeline - CheckIn: \(result != nil ? "Found" : "Not found"), NotableDay: \(day != nil ? "Found" : "Not found")")
|
||||||
|
|
||||||
|
let entry = CheckInEntry(date: currentDate, result: result, notableDay: day, error: nil, isLoading: false)
|
||||||
|
|
||||||
|
let nextUpdateDate: Date
|
||||||
|
if let result = result, let createdDate = result.createdDate {
|
||||||
|
let calendar = Calendar.current
|
||||||
|
if let tomorrow = calendar.date(byAdding: .day, value: 1, to: createdDate) {
|
||||||
|
nextUpdateDate = min(tomorrow, calendar.date(byAdding: .hour, value: 1, to: currentDate)!)
|
||||||
|
} else {
|
||||||
|
nextUpdateDate = calendar.date(byAdding: .hour, value: 1, to: currentDate)!
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nextUpdateDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[WidgetKit] [Provider] Next update at: \(nextUpdateDate)")
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .after(nextUpdateDate))
|
||||||
|
completion(timeline)
|
||||||
|
} catch {
|
||||||
|
print("[WidgetKit] [Provider] Error in getTimeline: \(error.localizedDescription)")
|
||||||
|
let entry = CheckInEntry(date: currentDate, result: nil, notableDay: nil, error: error.localizedDescription, isLoading: false)
|
||||||
|
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 10, to: currentDate)!
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
|
||||||
|
completion(timeline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckInWidgetEntryView: View {
|
||||||
|
var entry: Provider.Entry
|
||||||
|
@Environment(\.widgetFamily) var family
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if let result = entry.result {
|
||||||
|
CheckedInView(result: result, notableDay: entry.notableDay)
|
||||||
|
} else if entry.isLoading {
|
||||||
|
LoadingView()
|
||||||
|
} else if let error = entry.error {
|
||||||
|
ErrorView(error: error)
|
||||||
|
} else {
|
||||||
|
NotCheckedInView(notableDay: entry.notableDay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getLevelName(for level: Int) -> String {
|
||||||
|
let key = "checkInResultT\(level)"
|
||||||
|
return NSLocalizedString(key, comment: "Check-in result level name")
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func NotableDayView(notableDay: NotableDay) -> some View {
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
if !notableDay.isToday {
|
||||||
|
Text(NSLocalizedString("notableDayUpcoming", comment: "Upcoming"))
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
HStack(spacing: isAccessory ? 8 : 6) {
|
||||||
|
Image(systemName: "sparkles")
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
.font(isAccessory ? .caption : .subheadline)
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
if notableDay.isToday {
|
||||||
|
Text(String(format: NSLocalizedString("notableDayToday", comment: "{name} is today!"), notableDay.localName))
|
||||||
|
.font(isAccessory ? .caption : .footnote)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.lineLimit(2)
|
||||||
|
} else {
|
||||||
|
if let notableDate = notableDay.notableDate {
|
||||||
|
let dateString = isCompact ? formatDateCompact(notableDate) : formatDateRegular(notableDate)
|
||||||
|
Text(String(format: NSLocalizedString("notableDayIs", comment: "{date} is {name}"), dateString, notableDay.localName))
|
||||||
|
.font(isAccessory ? .caption : .footnote)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.lineLimit(2)
|
||||||
|
} else {
|
||||||
|
Text(notableDay.localName)
|
||||||
|
.font(isAccessory ? .caption : .footnote)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.lineLimit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if notableDay.isToday && !isAccessory {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: "star.fill")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
Text(NSLocalizedString("today", comment: "Today"))
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isCompact: Bool {
|
||||||
|
family == .systemSmall || isAccessory
|
||||||
|
}
|
||||||
|
|
||||||
|
private func formatDateCompact(_ date: Date) -> String {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateFormat = "M/d"
|
||||||
|
return formatter.string(from: date)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func formatDateRegular(_ date: Date) -> String {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateFormat = "MMM d, yyyy"
|
||||||
|
return formatter.string(from: date)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func CheckedInView(result: CheckInResult, notableDay: NotableDay?) -> some View {
|
||||||
|
Link(destination: URL(string: "solian://dashboard")!) {
|
||||||
|
VStack(alignment: .leading, spacing: isAccessory ? 2 : 8) {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: "flame.fill")
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
.font(isAccessory ? .caption : .title3)
|
||||||
|
Text(getLevelName(for: result.level))
|
||||||
|
.font(isAccessory ? .caption2 : .headline)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !result.tips.isEmpty {
|
||||||
|
if isAccessory {
|
||||||
|
let positiveTips = result.tips.filter { $0.isPositive }
|
||||||
|
let negativeTips = result.tips.filter { !$0.isPositive }
|
||||||
|
|
||||||
|
HStack(spacing: 2) {
|
||||||
|
if let positiveTip = positiveTips.first {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: "hand.thumbsup.fill")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Text(positiveTip.title)
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let negativeTip = negativeTips.first {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: "hand.thumbsdown.fill")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Text(negativeTip.title)
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
} else if family == .systemSmall {
|
||||||
|
let positiveTips = result.tips.filter { $0.isPositive }
|
||||||
|
let negativeTips = result.tips.filter { !$0.isPositive }
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
if let positiveTip = positiveTips.first {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: "hand.thumbsup.fill")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.green.opacity(0.8))
|
||||||
|
Text(positiveTip.title)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let negativeTip = negativeTips.first {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: "hand.thumbsdown.fill")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.red.opacity(0.8))
|
||||||
|
Text(negativeTip.title)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let positiveTips = result.tips.filter { $0.isPositive }
|
||||||
|
let negativeTips = result.tips.filter { !$0.isPositive }
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
if !positiveTips.isEmpty {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "hand.thumbsup.fill")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.green.opacity(0.8))
|
||||||
|
ForEach(Array(positiveTips.prefix(3)), id: \.title) { tip in
|
||||||
|
Text(tip.title)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
if tip.title != positiveTips.last?.title {
|
||||||
|
Text("•")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !negativeTips.isEmpty {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "hand.thumbsdown.fill")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.red.opacity(0.8))
|
||||||
|
ForEach(Array(negativeTips.prefix(3)), id: \.title) { tip in
|
||||||
|
Text(tip.title)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
if tip.title != negativeTips.last?.title {
|
||||||
|
Text("•")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if !isAccessory && family != .systemSmall {
|
||||||
|
Text("No fortune today")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let notableDay = notableDay {
|
||||||
|
NotableDayView(notableDay: notableDay)
|
||||||
|
}
|
||||||
|
|
||||||
|
if family == .systemLarge {
|
||||||
|
Spacer()
|
||||||
|
WidgetFooter()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(isAccessory ? 0 : (family == .systemSmall ? 6 : 12))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func WidgetFooter() -> some View {
|
||||||
|
HStack {
|
||||||
|
Text("Solian")
|
||||||
|
.font(.caption2)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isAccessory: Bool {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if case .accessoryRectangular = family {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func NotCheckedInView(notableDay: NotableDay?) -> some View {
|
||||||
|
Link(destination: URL(string: "solian://dashboard")!) {
|
||||||
|
VStack(alignment: .leading, spacing: isAccessory ? 2 : 8) {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: "flame.fill")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.font(isAccessory ? .caption : .title3)
|
||||||
|
Text(NSLocalizedString("checkIn", comment: "Check In"))
|
||||||
|
.font(isAccessory ? .caption2 : .headline)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAccessory {
|
||||||
|
Text(NSLocalizedString("tapToCheckIn", comment: "Tap to check in today"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
if let notableDay = notableDay {
|
||||||
|
NotableDayView(notableDay: notableDay)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
WidgetFooter()
|
||||||
|
} else if let notableDay = notableDay {
|
||||||
|
NotableDayView(notableDay: notableDay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(isAccessory ? 0 : (family == .systemSmall ? 6 : 12))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func LoadingView() -> some View {
|
||||||
|
VStack(alignment: .leading, spacing: isAccessory ? 2 : 8) {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
ProgressView()
|
||||||
|
.scaleEffect(isAccessory ? 0.6 : 0.8)
|
||||||
|
Text(NSLocalizedString("loading", comment: "Loading..."))
|
||||||
|
.font(isAccessory ? .caption2 : .caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAccessory {
|
||||||
|
Spacer()
|
||||||
|
WidgetFooter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(isAccessory ? 0 : 12)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func ErrorView(error: String) -> some View {
|
||||||
|
Link(destination: URL(string: "solian://dashboard")!) {
|
||||||
|
VStack(alignment: .leading, spacing: isAccessory ? 2 : 8) {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: "exclamationmark.triangle")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.font(isAccessory ? .caption : .title3)
|
||||||
|
Text(NSLocalizedString("error", comment: "Error"))
|
||||||
|
.font(isAccessory ? .caption2 : .headline)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAccessory {
|
||||||
|
Text(NSLocalizedString("openAppToRefresh", comment: "Open app to refresh"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Text(error)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.lineLimit(nil)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
WidgetFooter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(isAccessory ? 0 : (family == .systemSmall ? 6 : 12))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckInWidgetRootView: View {
|
||||||
|
var entry: Provider.Entry
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
ZStack {
|
||||||
|
CheckInWidgetEntryView(entry: entry)
|
||||||
|
|
||||||
|
if entry.result != nil || entry.notableDay != nil {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
Image(colorScheme == .dark ? "CloudyLambDark" : "CloudyLamb")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(
|
||||||
|
width: geometry.size.width * 0.9,
|
||||||
|
height: geometry.size.width * 0.9
|
||||||
|
)
|
||||||
|
.opacity(0.18)
|
||||||
|
.mask(
|
||||||
|
LinearGradient(
|
||||||
|
gradient: Gradient(colors: [
|
||||||
|
Color.white,
|
||||||
|
Color.white,
|
||||||
|
Color.clear
|
||||||
|
]),
|
||||||
|
startPoint: .topLeading,
|
||||||
|
endPoint: .bottomTrailing
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.position(
|
||||||
|
x: geometry.size.width * 0.9,
|
||||||
|
y: 20
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.allowsHitTesting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
.padding(.vertical, 8)
|
||||||
|
} else {
|
||||||
|
CheckInWidgetEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SolianCheckInWidget: Widget {
|
||||||
|
let kind: String = "SolianCheckInWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: Provider()) { entry in
|
||||||
|
CheckInWidgetRootView(entry: entry)
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Check In")
|
||||||
|
.description("View your daily check-in status")
|
||||||
|
.supportedFamilies(supportedFamilies)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var supportedFamilies: [WidgetFamily] {
|
||||||
|
#if os(iOS)
|
||||||
|
return [.systemSmall, .systemMedium, .systemLarge, .accessoryRectangular]
|
||||||
|
#else
|
||||||
|
return [.systemSmall, .systemMedium, .systemLarge]
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemSmall) {
|
||||||
|
SolianCheckInWidget()
|
||||||
|
} timeline: {
|
||||||
|
CheckInEntry(date: .now, result: nil, notableDay: nil, error: nil, isLoading: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemMedium) {
|
||||||
|
SolianCheckInWidget()
|
||||||
|
} timeline: {
|
||||||
|
CheckInEntry(
|
||||||
|
date: .now,
|
||||||
|
result: CheckInResult(
|
||||||
|
id: "test-id",
|
||||||
|
level: 2,
|
||||||
|
rewardPoints: 10,
|
||||||
|
rewardExperience: 100,
|
||||||
|
tips: [
|
||||||
|
CheckInTip(isPositive: true, title: "Good Luck", content: "Great day"),
|
||||||
|
CheckInTip(isPositive: true, title: "Creative", content: "Inspiration"),
|
||||||
|
CheckInTip(isPositive: false, title: "Shopping", content: "Expensive")
|
||||||
|
],
|
||||||
|
accountId: "account-id",
|
||||||
|
account: nil,
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
notableDay: NotableDay(
|
||||||
|
date: ISO8601DateFormatter().string(from: Calendar.current.date(byAdding: .day, value: 5, to: Date())!),
|
||||||
|
localName: "Christmas",
|
||||||
|
globalName: "Christmas",
|
||||||
|
countryCode: nil,
|
||||||
|
localizableKey: nil,
|
||||||
|
holidays: []
|
||||||
|
),
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
#Preview(as: .accessoryRectangular) {
|
||||||
|
SolianCheckInWidget()
|
||||||
|
} timeline: {
|
||||||
|
CheckInEntry(
|
||||||
|
date: .now,
|
||||||
|
result: CheckInResult(
|
||||||
|
id: "test-id",
|
||||||
|
level: 4,
|
||||||
|
rewardPoints: 50,
|
||||||
|
rewardExperience: 500,
|
||||||
|
tips: [
|
||||||
|
CheckInTip(isPositive: true, title: "Lucky", content: "Great fortune"),
|
||||||
|
CheckInTip(isPositive: true, title: "Success", content: "Opportunity")
|
||||||
|
],
|
||||||
|
accountId: "account-id",
|
||||||
|
account: nil,
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
notableDay: NotableDay(
|
||||||
|
date: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
localName: "New Year",
|
||||||
|
globalName: "New Year",
|
||||||
|
countryCode: nil,
|
||||||
|
localizableKey: nil,
|
||||||
|
holidays: []
|
||||||
|
),
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
937
ios/SolianWidgetExtension/SolianNotificationWidget.swift
Normal file
937
ios/SolianWidgetExtension/SolianNotificationWidget.swift
Normal file
@@ -0,0 +1,937 @@
|
|||||||
|
//
|
||||||
|
// SolianNotificationWidget.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/4.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
// MARK: - Notification Widget
|
||||||
|
|
||||||
|
struct NotificationMeta: Codable {
|
||||||
|
let pfp: String?
|
||||||
|
let images: [String]?
|
||||||
|
let actionUri: String?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case pfp
|
||||||
|
case images
|
||||||
|
case actionUri = "action_uri"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnNotification: Codable, Identifiable {
|
||||||
|
let id: String
|
||||||
|
let topic: String
|
||||||
|
let title: String
|
||||||
|
let subtitle: String
|
||||||
|
let content: String
|
||||||
|
let meta: NotificationMeta?
|
||||||
|
let priority: Int
|
||||||
|
let viewedAt: String?
|
||||||
|
let accountId: String
|
||||||
|
let createdAt: String
|
||||||
|
let updatedAt: String
|
||||||
|
let deletedAt: String?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case topic
|
||||||
|
case title
|
||||||
|
case subtitle
|
||||||
|
case content
|
||||||
|
case meta
|
||||||
|
case priority
|
||||||
|
case viewedAt = "viewed_at"
|
||||||
|
case accountId = "account_id"
|
||||||
|
case createdAt = "created_at"
|
||||||
|
case updatedAt = "updated_at"
|
||||||
|
case deletedAt = "deleted_at"
|
||||||
|
}
|
||||||
|
|
||||||
|
var createdDate: Date? {
|
||||||
|
let formatter = ISO8601DateFormatter()
|
||||||
|
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||||
|
|
||||||
|
if let date = formatter.date(from: createdAt) {
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for timestamps without fractional seconds
|
||||||
|
formatter.formatOptions = [.withInternetDateTime]
|
||||||
|
return formatter.date(from: createdAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isUnread: Bool {
|
||||||
|
return viewedAt == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTopicIcon() -> String {
|
||||||
|
switch topic {
|
||||||
|
case "post.replies":
|
||||||
|
return "arrow.uturn.backward"
|
||||||
|
case "wallet.transactions":
|
||||||
|
return "wallet.pass"
|
||||||
|
case "relationships.friends.request":
|
||||||
|
return "person.badge.plus"
|
||||||
|
case "invites.chat":
|
||||||
|
return "message.badge"
|
||||||
|
case "invites.realm":
|
||||||
|
return "globe"
|
||||||
|
case "auth.login":
|
||||||
|
return "arrow.right.square"
|
||||||
|
case "posts.new":
|
||||||
|
return "doc.badge.plus"
|
||||||
|
case "wallet.orders.paid":
|
||||||
|
return "baggage"
|
||||||
|
case "posts.reactions.new":
|
||||||
|
return "face.smiling"
|
||||||
|
default:
|
||||||
|
return "bell"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotificationEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let notifications: [SnNotification]?
|
||||||
|
let unreadCount: Int
|
||||||
|
let error: String?
|
||||||
|
let isLoading: Bool
|
||||||
|
|
||||||
|
static func placeholder() -> NotificationEntry {
|
||||||
|
NotificationEntry(date: Date(), notifications: nil, unreadCount: 0, error: nil, isLoading: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotificationService {
|
||||||
|
private let networkService = WidgetNetworkService()
|
||||||
|
|
||||||
|
private lazy var session: URLSession = {
|
||||||
|
let configuration = URLSessionConfiguration.ephemeral
|
||||||
|
configuration.timeoutIntervalForRequest = 10.0
|
||||||
|
configuration.timeoutIntervalForResource = 10.0
|
||||||
|
configuration.waitsForConnectivity = false
|
||||||
|
return URLSession(configuration: configuration)
|
||||||
|
}()
|
||||||
|
|
||||||
|
func fetchRecentNotifications(take: Int = 5) async throws -> [SnNotification] {
|
||||||
|
if take == 0 {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let token = networkService.token else {
|
||||||
|
throw RemoteError.missingCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseURL = networkService.baseURL
|
||||||
|
guard let url = URL(string: "\(baseURL)/ring/notifications?unmark=true&take=\(take)") else {
|
||||||
|
throw RemoteError.invalidURL
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||||
|
request.timeoutInterval = 10.0
|
||||||
|
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
|
||||||
|
guard let httpResponse = response as? HTTPURLResponse else {
|
||||||
|
throw RemoteError.invalidResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
switch httpResponse.statusCode {
|
||||||
|
case 200...299:
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
let notifications = try decoder.decode([SnNotification].self, from: data)
|
||||||
|
return notifications
|
||||||
|
case 404:
|
||||||
|
return []
|
||||||
|
default:
|
||||||
|
throw RemoteError.httpError(httpResponse.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchUnreadCount() async throws -> Int {
|
||||||
|
guard let token = networkService.token else {
|
||||||
|
throw RemoteError.missingCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseURL = networkService.baseURL
|
||||||
|
guard let url = URL(string: "\(baseURL)/ring/notifications/count") else {
|
||||||
|
throw RemoteError.invalidURL
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||||
|
request.timeoutInterval = 10.0
|
||||||
|
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
|
||||||
|
guard let httpResponse = response as? HTTPURLResponse else {
|
||||||
|
throw RemoteError.invalidResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
switch httpResponse.statusCode {
|
||||||
|
case 200...299:
|
||||||
|
if let count = try? JSONSerialization.jsonObject(with: data) as? Int {
|
||||||
|
return count
|
||||||
|
} else if let count = try? JSONSerialization.jsonObject(with: data) as? Double {
|
||||||
|
return Int(count)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
case 404:
|
||||||
|
return 0
|
||||||
|
default:
|
||||||
|
throw RemoteError.httpError(httpResponse.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotificationProvider: TimelineProvider {
|
||||||
|
private let notificationService = NotificationService()
|
||||||
|
|
||||||
|
func placeholder(in context: Context) -> NotificationEntry {
|
||||||
|
NotificationEntry.placeholder()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(in context: Context, completion: @escaping (NotificationEntry) -> ()) {
|
||||||
|
Task {
|
||||||
|
print("[WidgetKit] [NotificationProvider] Getting snapshot...")
|
||||||
|
async let notifications = try? await notificationService.fetchRecentNotifications(take: 5)
|
||||||
|
async let unreadCount = try? await notificationService.fetchUnreadCount()
|
||||||
|
|
||||||
|
let notifs = try? await notifications
|
||||||
|
let unread = (try? await unreadCount) ?? 0
|
||||||
|
|
||||||
|
print("[WidgetKit] [NotificationProvider] Snapshot - Notifications: \(notifs?.count ?? 0), Unread: \(unread)")
|
||||||
|
|
||||||
|
let entry = NotificationEntry(date: Date(), notifications: notifs, unreadCount: unread, error: nil, isLoading: false)
|
||||||
|
completion(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
Task {
|
||||||
|
let currentDate = Date()
|
||||||
|
print("[WidgetKit] [NotificationProvider] Getting timeline at \(currentDate)...")
|
||||||
|
|
||||||
|
do {
|
||||||
|
let takeLimit: Int
|
||||||
|
switch context.family {
|
||||||
|
case .systemSmall:
|
||||||
|
takeLimit = 0
|
||||||
|
case .systemMedium:
|
||||||
|
takeLimit = 1
|
||||||
|
case .systemLarge:
|
||||||
|
takeLimit = 3
|
||||||
|
default:
|
||||||
|
takeLimit = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
async let notifications = try await notificationService.fetchRecentNotifications(take: takeLimit)
|
||||||
|
async let unreadCount = try await notificationService.fetchUnreadCount()
|
||||||
|
|
||||||
|
let notifs = try await notifications
|
||||||
|
let unread = try await unreadCount
|
||||||
|
|
||||||
|
print("[WidgetKit] [NotificationProvider] Timeline - Notifications: \(notifs.count), Unread: \(unread)")
|
||||||
|
|
||||||
|
let entry = NotificationEntry(date: currentDate, notifications: notifs, unreadCount: unread, error: nil, isLoading: false)
|
||||||
|
|
||||||
|
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 15, to: currentDate)!
|
||||||
|
print("[WidgetKit] [NotificationProvider] Next update at: \(nextUpdate)")
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
|
||||||
|
completion(timeline)
|
||||||
|
} catch {
|
||||||
|
print("[WidgetKit] [NotificationProvider] Error in getTimeline: \(error.localizedDescription)")
|
||||||
|
let entry = NotificationEntry(date: currentDate, notifications: nil, unreadCount: 0, error: error.localizedDescription, isLoading: false)
|
||||||
|
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
|
||||||
|
completion(timeline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotificationWidgetEntryView: View {
|
||||||
|
var entry: NotificationProvider.Entry
|
||||||
|
@Environment(\.widgetFamily) var family
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if let notifications = entry.notifications, !notifications.isEmpty {
|
||||||
|
HasNotificationsView(notifications: notifications, unreadCount: entry.unreadCount)
|
||||||
|
} else if entry.isLoading {
|
||||||
|
LoadingView()
|
||||||
|
} else if let error = entry.error {
|
||||||
|
ErrorView(error: error)
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isCompact: Bool {
|
||||||
|
family == .systemSmall || isAccessory
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isAccessory: Bool {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if case .accessoryRectangular = family {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if case .accessoryCircular = family {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isCircular: Bool {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if case .accessoryCircular = family {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func HasNotificationsView(notifications: [SnNotification], unreadCount: Int) -> some View {
|
||||||
|
Link(destination: URL(string: "solian://notifications")!) {
|
||||||
|
if isCompact {
|
||||||
|
if isAccessory {
|
||||||
|
if isCircular {
|
||||||
|
ZStack {
|
||||||
|
Image(systemName: "bell.fill")
|
||||||
|
.font(.system(size: 20))
|
||||||
|
.foregroundColor(unreadCount > 0 ? .orange : .gray)
|
||||||
|
|
||||||
|
if unreadCount > 0 {
|
||||||
|
Text("\(min(unreadCount, 99))")
|
||||||
|
.font(.system(size: 10, weight: .bold))
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.padding(4)
|
||||||
|
.background(Circle().fill(Color.blue))
|
||||||
|
.offset(x: 12, y: -12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: "bell.fill")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
.padding(.leading, 1.5)
|
||||||
|
|
||||||
|
Text(NSLocalizedString("notifications", comment: "Notifications"))
|
||||||
|
.font(.caption2)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if unreadCount > 0 {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Text("\(unreadCount)")
|
||||||
|
.font(.caption2)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.padding(.horizontal, 6)
|
||||||
|
.background(
|
||||||
|
Capsule()
|
||||||
|
.fill(Color.blue.opacity(0.5))
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(NSLocalizedString("unread", comment: "unread"))
|
||||||
|
.font(.caption2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text("on the Solar Network")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.padding(.horizontal, 1.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "bell.fill")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
|
||||||
|
Text(NSLocalizedString("notifications", comment: "Notifications"))
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}.padding(.bottom, 8)
|
||||||
|
|
||||||
|
Spacer(minLength: 2)
|
||||||
|
|
||||||
|
if unreadCount > 0 {
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text("\(unreadCount)")
|
||||||
|
.font(.system(.largeTitle, design: .rounded))
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(minLength: 2)
|
||||||
|
|
||||||
|
if unreadCount > 0 {
|
||||||
|
Text(NSLocalizedString("unreadNotifications", comment: "unread notifications"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(2)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
} else {
|
||||||
|
Text(NSLocalizedString("noUnreadNotifications", comment: "no unread notifications"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(12)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "bell.fill")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
|
||||||
|
Text(NSLocalizedString("notifications", comment: "Notifications"))
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if unreadCount > 0 {
|
||||||
|
Text("\(unreadCount)")
|
||||||
|
.font(.caption)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.padding(.horizontal, 6)
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
.background(.blue)
|
||||||
|
.clipShape(Capsule())
|
||||||
|
}
|
||||||
|
}.padding(.bottom, 8)
|
||||||
|
|
||||||
|
let displayCount = family == .systemMedium ? 1 : 5
|
||||||
|
let displayNotifications = Array(notifications.prefix(displayCount))
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
ForEach(displayNotifications) { notification in
|
||||||
|
NotificationItemView(notification: notification, compact: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if family == .systemMedium {
|
||||||
|
Spacer()
|
||||||
|
} else {
|
||||||
|
Spacer()
|
||||||
|
Text(NSLocalizedString("tapToViewAll", comment: "Tap to view all notifications"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func NotificationItemView(notification: SnNotification, compact: Bool) -> some View {
|
||||||
|
HStack(alignment: .top, spacing: compact ? 6 : 12) {
|
||||||
|
if compact {
|
||||||
|
Image(systemName: notification.getTopicIcon())
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
} else {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.fill(Color.gray.opacity(0.2))
|
||||||
|
.frame(width: 32, height: 32)
|
||||||
|
|
||||||
|
Image(systemName: notification.getTopicIcon())
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text(notification.title)
|
||||||
|
.font(compact ? .caption : .subheadline)
|
||||||
|
.fontWeight(notification.isUnread ? .semibold : .regular)
|
||||||
|
.lineLimit(1)
|
||||||
|
|
||||||
|
if !compact && !notification.subtitle.isEmpty {
|
||||||
|
Text(notification.subtitle)
|
||||||
|
.font(.caption)
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !compact && !notification.content.isEmpty {
|
||||||
|
Text(notification.content)
|
||||||
|
.font(.caption2)
|
||||||
|
.lineLimit(2)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let createdDate = notification.createdDate {
|
||||||
|
Text(formatRelativeTime(createdDate))
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.padding(.top, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if notification.isUnread {
|
||||||
|
Circle()
|
||||||
|
.fill(Color.blue)
|
||||||
|
.frame(width: compact ? 6 : 8, height: compact ? 6 : 8)
|
||||||
|
.padding(.trailing, 6)
|
||||||
|
.padding(.top, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.vertical, compact ? 2 : 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func NotificationCompactItem(notification: SnNotification) -> some View {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: notification.getTopicIcon())
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Text(notification.title)
|
||||||
|
.font(.caption2)
|
||||||
|
.lineLimit(1)
|
||||||
|
.fontWeight(notification.isUnread ? .semibold : .regular)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func EmptyView() -> some View {
|
||||||
|
Link(destination: URL(string: "solian://notifications")!) {
|
||||||
|
if isCircular {
|
||||||
|
ZStack {
|
||||||
|
Image(systemName: "bell")
|
||||||
|
.font(.system(size: 20))
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: isAccessory ? 4 : 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "bell")
|
||||||
|
.font(isAccessory ? .caption : .title3)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Text(NSLocalizedString("notifications", comment: "Notifications"))
|
||||||
|
.font(isAccessory ? .caption2 : .headline)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAccessory {
|
||||||
|
Text(NSLocalizedString("noNotifications", comment: "No notifications yet"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(isAccessory ? 4 : 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func LoadingView() -> some View {
|
||||||
|
if isCircular {
|
||||||
|
ProgressView()
|
||||||
|
.scaleEffect(0.8)
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: isAccessory ? 4 : 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
ProgressView()
|
||||||
|
.scaleEffect(isAccessory ? 0.6 : 0.8)
|
||||||
|
Text(NSLocalizedString("loading", comment: "Loading..."))
|
||||||
|
.font(isAccessory ? .caption2 : .caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAccessory {
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(isAccessory ? 4 : 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func ErrorView(error: String) -> some View {
|
||||||
|
Link(destination: URL(string: "solian://notifications")!) {
|
||||||
|
if isCircular {
|
||||||
|
ZStack {
|
||||||
|
Image(systemName: "exclamationmark.triangle")
|
||||||
|
.font(.system(size: 20))
|
||||||
|
.foregroundColor(.red)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: isAccessory ? 4 : 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "exclamationmark.triangle")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.font(isAccessory ? .caption : .title3)
|
||||||
|
|
||||||
|
Text(NSLocalizedString("error", comment: "Error"))
|
||||||
|
.font(isAccessory ? .caption2 : .headline)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAccessory {
|
||||||
|
Text(NSLocalizedString("openAppToRefresh", comment: "Open app to refresh"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Text(error)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.lineLimit(nil)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(isAccessory ? 4 : 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func formatRelativeTime(_ date: Date) -> String {
|
||||||
|
let now = Date()
|
||||||
|
let interval = now.timeIntervalSince(date)
|
||||||
|
|
||||||
|
if interval < 60 {
|
||||||
|
return NSLocalizedString("justNow", comment: "Just now")
|
||||||
|
} else if interval < 3600 {
|
||||||
|
let minutes = Int(interval / 60)
|
||||||
|
return String(format: NSLocalizedString("minutesAgo", comment: "%d min ago"), minutes)
|
||||||
|
} else if interval < 86400 {
|
||||||
|
let hours = Int(interval / 3600)
|
||||||
|
return String(format: NSLocalizedString("hoursAgo", comment: "%d hr ago"), hours)
|
||||||
|
} else {
|
||||||
|
let days = Int(interval / 86400)
|
||||||
|
return String(format: NSLocalizedString("daysAgo", comment: "%d d ago"), days)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotificationWidgetRootView: View {
|
||||||
|
var entry: NotificationProvider.Entry
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
ZStack {
|
||||||
|
NotificationWidgetEntryView(entry: entry)
|
||||||
|
|
||||||
|
if let notifications = entry.notifications, !notifications.isEmpty {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
Image(colorScheme == .dark ? "CloudyLambDark" : "CloudyLamb")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(
|
||||||
|
width: geometry.size.width * 0.9,
|
||||||
|
height: geometry.size.width * 0.9
|
||||||
|
)
|
||||||
|
.opacity(0.12)
|
||||||
|
.mask(
|
||||||
|
LinearGradient(
|
||||||
|
gradient: Gradient(colors: [
|
||||||
|
Color.white,
|
||||||
|
Color.white,
|
||||||
|
Color.clear
|
||||||
|
]),
|
||||||
|
startPoint: .topLeading,
|
||||||
|
endPoint: .bottomTrailing
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.position(
|
||||||
|
x: geometry.size.width * 0.85,
|
||||||
|
y: 20
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.allowsHitTesting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
.padding(.vertical, 8)
|
||||||
|
} else {
|
||||||
|
NotificationWidgetEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SolianNotificationWidget: Widget {
|
||||||
|
let kind: String = "SolianNotificationWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: NotificationProvider()) { entry in
|
||||||
|
NotificationWidgetRootView(entry: entry)
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Notifications")
|
||||||
|
.description("View your recent notifications")
|
||||||
|
.supportedFamilies(supportedFamilies)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var supportedFamilies: [WidgetFamily] {
|
||||||
|
#if os(iOS)
|
||||||
|
return [.systemSmall, .systemMedium, .systemLarge, .accessoryRectangular, .accessoryCircular]
|
||||||
|
#else
|
||||||
|
return [.systemSmall, .systemMedium, .systemLarge]
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
#Preview(as: .accessoryRectangular) {
|
||||||
|
SolianNotificationWidget()
|
||||||
|
} timeline: {
|
||||||
|
NotificationEntry(
|
||||||
|
date: .now,
|
||||||
|
notifications: [
|
||||||
|
SnNotification(
|
||||||
|
id: "1",
|
||||||
|
topic: "post.replies",
|
||||||
|
title: "New reply to your post",
|
||||||
|
subtitle: "Someone replied to your message",
|
||||||
|
content: "This is notification content",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: nil,
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
SnNotification(
|
||||||
|
id: "2",
|
||||||
|
topic: "relationships.friends.request",
|
||||||
|
title: "New friend request",
|
||||||
|
subtitle: "You have a pending friend request",
|
||||||
|
content: "Someone wants to be your friend",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-3600)),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
)
|
||||||
|
],
|
||||||
|
unreadCount: 1,
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#Preview(as: .systemSmall) {
|
||||||
|
SolianNotificationWidget()
|
||||||
|
} timeline: {
|
||||||
|
NotificationEntry(
|
||||||
|
date: .now,
|
||||||
|
notifications: [
|
||||||
|
SnNotification(
|
||||||
|
id: "1",
|
||||||
|
topic: "post.replies",
|
||||||
|
title: "New reply to your post",
|
||||||
|
subtitle: "Someone replied to your message",
|
||||||
|
content: "This is notification content",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: nil,
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
SnNotification(
|
||||||
|
id: "2",
|
||||||
|
topic: "relationships.friends.request",
|
||||||
|
title: "New friend request",
|
||||||
|
subtitle: "You have a pending friend request",
|
||||||
|
content: "Someone wants to be your friend",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-3600)),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
)
|
||||||
|
],
|
||||||
|
unreadCount: 1,
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemMedium) {
|
||||||
|
SolianNotificationWidget()
|
||||||
|
} timeline: {
|
||||||
|
NotificationEntry(
|
||||||
|
date: .now,
|
||||||
|
notifications: [
|
||||||
|
SnNotification(
|
||||||
|
id: "1",
|
||||||
|
topic: "post.replies",
|
||||||
|
title: "New reply to your post",
|
||||||
|
subtitle: "Someone replied to your message",
|
||||||
|
content: "This is notification content",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: nil,
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
SnNotification(
|
||||||
|
id: "2",
|
||||||
|
topic: "relationships.friends.request",
|
||||||
|
title: "New friend request",
|
||||||
|
subtitle: "You have a pending friend request",
|
||||||
|
content: "Someone wants to be your friend",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: nil,
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-3600)),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
SnNotification(
|
||||||
|
id: "3",
|
||||||
|
topic: "invites.chat",
|
||||||
|
title: "New chat invite",
|
||||||
|
subtitle: "You've been invited to a chat",
|
||||||
|
content: "Join the conversation",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-86400)),
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-86400)),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
)
|
||||||
|
],
|
||||||
|
unreadCount: 2,
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
#Preview(as: .systemLarge) {
|
||||||
|
SolianNotificationWidget()
|
||||||
|
} timeline: {
|
||||||
|
NotificationEntry(
|
||||||
|
date: .now,
|
||||||
|
notifications: [
|
||||||
|
SnNotification(
|
||||||
|
id: "1",
|
||||||
|
topic: "post.replies",
|
||||||
|
title: "New reply",
|
||||||
|
subtitle: "Someone replied",
|
||||||
|
content: "Content",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: nil,
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
SnNotification(
|
||||||
|
id: "2",
|
||||||
|
topic: "relationships.friends.request",
|
||||||
|
title: "New friend request",
|
||||||
|
subtitle: "You have a pending friend request",
|
||||||
|
content: "Someone wants to be your friend",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: nil,
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-3600)),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
),
|
||||||
|
SnNotification(
|
||||||
|
id: "3",
|
||||||
|
topic: "invites.chat",
|
||||||
|
title: "New chat invite",
|
||||||
|
subtitle: "You've been invited to a chat",
|
||||||
|
content: "Join the conversation",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-86400)),
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-86400)),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
)
|
||||||
|
],
|
||||||
|
unreadCount: 3,
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .accessoryCircular) {
|
||||||
|
SolianNotificationWidget()
|
||||||
|
} timeline: {
|
||||||
|
NotificationEntry(
|
||||||
|
date: .now,
|
||||||
|
notifications: [
|
||||||
|
SnNotification(
|
||||||
|
id: "1",
|
||||||
|
topic: "post.replies",
|
||||||
|
title: "New reply",
|
||||||
|
subtitle: "Someone replied",
|
||||||
|
content: "Content",
|
||||||
|
meta: nil,
|
||||||
|
priority: 0,
|
||||||
|
viewedAt: nil,
|
||||||
|
accountId: "acc-1",
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
deletedAt: nil
|
||||||
|
)
|
||||||
|
],
|
||||||
|
unreadCount: 5,
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
549
ios/SolianWidgetExtension/SolianPostShuffleWidget.swift
Normal file
549
ios/SolianWidgetExtension/SolianPostShuffleWidget.swift
Normal file
@@ -0,0 +1,549 @@
|
|||||||
|
//
|
||||||
|
// SolianPostShuffleWidget.swift
|
||||||
|
// SolianWidgetExtension
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/4.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SnPostPublisher: Codable {
|
||||||
|
let id: String
|
||||||
|
let name: String
|
||||||
|
let nick: String?
|
||||||
|
let description: String?
|
||||||
|
let picture: SnCloudFile?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case name
|
||||||
|
case nick
|
||||||
|
case description
|
||||||
|
case picture
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnCloudFile: Codable {
|
||||||
|
let id: String
|
||||||
|
let url: String?
|
||||||
|
let thumbnail: String?
|
||||||
|
let mimeType: String?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case url
|
||||||
|
case thumbnail
|
||||||
|
case mimeType = "mimetype"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnPost: Codable, Identifiable {
|
||||||
|
let id: String
|
||||||
|
let title: String?
|
||||||
|
let description: String?
|
||||||
|
let content: String?
|
||||||
|
let publisher: SnPostPublisher
|
||||||
|
let tags: [SnPostTag]?
|
||||||
|
let createdAt: String?
|
||||||
|
let updatedAt: String?
|
||||||
|
let attachments: [SnCloudFile]?
|
||||||
|
|
||||||
|
var createdDate: Date? {
|
||||||
|
guard let createdAt = createdAt else { return nil }
|
||||||
|
|
||||||
|
let formatter = ISO8601DateFormatter()
|
||||||
|
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||||
|
|
||||||
|
if let date = formatter.date(from: createdAt) {
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for timestamps without fractional seconds
|
||||||
|
formatter.formatOptions = [.withInternetDateTime]
|
||||||
|
return formatter.date(from: createdAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasTitle: Bool {
|
||||||
|
guard let title = title else { return false }
|
||||||
|
return !title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasDescription: Bool {
|
||||||
|
guard let description = description else { return false }
|
||||||
|
return !description.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasContent: Bool {
|
||||||
|
guard let content = content else { return false }
|
||||||
|
return !content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
var attachmentCount: Int {
|
||||||
|
attachments?.count ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case title
|
||||||
|
case description
|
||||||
|
case content
|
||||||
|
case publisher
|
||||||
|
case tags
|
||||||
|
case createdAt = "created_at"
|
||||||
|
case updatedAt = "updated_at"
|
||||||
|
case attachments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnPostTag: Codable {
|
||||||
|
let id: String
|
||||||
|
let slug: String
|
||||||
|
let name: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
class PostShuffleService {
|
||||||
|
private let networkService = WidgetNetworkService()
|
||||||
|
|
||||||
|
private lazy var session: URLSession = {
|
||||||
|
let configuration = URLSessionConfiguration.ephemeral
|
||||||
|
configuration.timeoutIntervalForRequest = 10.0
|
||||||
|
configuration.timeoutIntervalForResource = 10.0
|
||||||
|
configuration.waitsForConnectivity = false
|
||||||
|
return URLSession(configuration: configuration)
|
||||||
|
}()
|
||||||
|
|
||||||
|
func fetchRandomPost() async throws -> SnPost? {
|
||||||
|
guard let token = networkService.token else {
|
||||||
|
throw RemoteError.missingCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
let baseURL = networkService.baseURL
|
||||||
|
guard let url = URL(string: "\(baseURL)/sphere/posts?shuffle=true&take=1") else {
|
||||||
|
throw RemoteError.invalidURL
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||||
|
request.timeoutInterval = 10.0
|
||||||
|
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
|
||||||
|
guard let httpResponse = response as? HTTPURLResponse else {
|
||||||
|
throw RemoteError.invalidResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
switch httpResponse.statusCode {
|
||||||
|
case 200...299:
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
let posts = try decoder.decode([SnPost].self, from: data)
|
||||||
|
return posts.first
|
||||||
|
case 404:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
throw RemoteError.httpError(httpResponse.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PostShuffleEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let post: SnPost?
|
||||||
|
let error: String?
|
||||||
|
let isLoading: Bool
|
||||||
|
|
||||||
|
static func placeholder() -> PostShuffleEntry {
|
||||||
|
PostShuffleEntry(date: Date(), post: nil, error: nil, isLoading: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PostShuffleProvider: TimelineProvider {
|
||||||
|
private let postShuffleService = PostShuffleService()
|
||||||
|
|
||||||
|
func placeholder(in context: Context) -> PostShuffleEntry {
|
||||||
|
PostShuffleEntry.placeholder()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(in context: Context, completion: @escaping (PostShuffleEntry) -> ()) {
|
||||||
|
Task {
|
||||||
|
print("[WidgetKit] [PostShuffleProvider] Getting snapshot...")
|
||||||
|
let post = try? await postShuffleService.fetchRandomPost()
|
||||||
|
|
||||||
|
print("[WidgetKit] [PostShuffleProvider] Snapshot - Post: \(post != nil ? "Found" : "Not found")")
|
||||||
|
|
||||||
|
let entry = PostShuffleEntry(date: Date(), post: post, error: nil, isLoading: false)
|
||||||
|
completion(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
Task {
|
||||||
|
let currentDate = Date()
|
||||||
|
print("[WidgetKit] [PostShuffleProvider] Getting timeline at \(currentDate)...")
|
||||||
|
|
||||||
|
do {
|
||||||
|
let post = try await postShuffleService.fetchRandomPost()
|
||||||
|
|
||||||
|
print("[WidgetKit] [PostShuffleProvider] Timeline - Post: \(post != nil ? "Found" : "Not found")")
|
||||||
|
|
||||||
|
let entry = PostShuffleEntry(date: currentDate, post: post, error: nil, isLoading: false)
|
||||||
|
|
||||||
|
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 10, to: currentDate)!
|
||||||
|
print("[WidgetKit] [PostShuffleProvider] Next update at: \(nextUpdate)")
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
|
||||||
|
completion(timeline)
|
||||||
|
} catch {
|
||||||
|
print("[WidgetKit] [PostShuffleProvider] Error in getTimeline: \(error.localizedDescription)")
|
||||||
|
let entry = PostShuffleEntry(date: currentDate, post: nil, error: error.localizedDescription, isLoading: false)
|
||||||
|
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)!
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
|
||||||
|
completion(timeline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PostShuffleWidgetEntryView: View {
|
||||||
|
var entry: PostShuffleProvider.Entry
|
||||||
|
@Environment(\.widgetFamily) var family
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if let post = entry.post {
|
||||||
|
PostContentView(post: post)
|
||||||
|
} else if entry.isLoading {
|
||||||
|
LoadingView()
|
||||||
|
} else if let error = entry.error {
|
||||||
|
ErrorView(error: error)
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func PostContentView(post: SnPost) -> some View {
|
||||||
|
Link(destination: URL(string: "solian://posts/\(post.id)")!) {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
HStack(alignment: .top, spacing: 8) {
|
||||||
|
if let avatarUrl = post.publisher.picture?.url ?? post.publisher.picture?.thumbnail {
|
||||||
|
AsyncImage(url: URL(string: avatarUrl)) { phase in
|
||||||
|
switch phase {
|
||||||
|
case .success(let image):
|
||||||
|
image
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
case .failure(_):
|
||||||
|
Circle()
|
||||||
|
.fill(Color.gray.opacity(0.3))
|
||||||
|
default:
|
||||||
|
Circle()
|
||||||
|
.fill(Color.gray.opacity(0.3))
|
||||||
|
.overlay(
|
||||||
|
ProgressView()
|
||||||
|
.scaleEffect(0.5)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
.clipShape(Circle())
|
||||||
|
} else {
|
||||||
|
Circle()
|
||||||
|
.fill(Color.gray.opacity(0.3))
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text(post.publisher.nick ?? post.publisher.name)
|
||||||
|
.font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.lineLimit(1)
|
||||||
|
|
||||||
|
if let createdDate = post.createdDate {
|
||||||
|
Text(formatRelativeTime(createdDate))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.attachmentCount > 0 {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Image(systemName: "paperclip")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Text("\(post.attachmentCount)")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.hasTitle {
|
||||||
|
Text(post.title!)
|
||||||
|
.font(family == .systemMedium ? .subheadline : .body)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.lineLimit(family == .systemMedium ? 2 : 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.hasDescription {
|
||||||
|
Text(post.description!)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(family == .systemMedium ? 2 : 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.hasContent {
|
||||||
|
Text(post.content!)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.lineLimit(family == .systemMedium ? 3 : 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let tags = post.tags, !tags.isEmpty {
|
||||||
|
let displayTags = Array(tags.prefix(family == .systemMedium ? 2 : 4))
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
ForEach(displayTags, id: \.id) { tag in
|
||||||
|
Text("#\(tag.name ?? tag.slug)")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.blue)
|
||||||
|
.padding(.horizontal, 6)
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
.background(Color.blue.opacity(0.1))
|
||||||
|
.clipShape(Capsule())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func EmptyView() -> some View {
|
||||||
|
Link(destination: URL(string: "solian://posts/shuffle")!) {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "text.alignleft")
|
||||||
|
.font(.title3)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(NSLocalizedString("noPostsAvailable", comment: "No posts available"))
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text(NSLocalizedString("tapToRefresh", comment: "Tap to refresh"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
.padding(12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func LoadingView() -> some View {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
ProgressView()
|
||||||
|
.scaleEffect(0.8)
|
||||||
|
Text(NSLocalizedString("loadingPost", comment: "Loading post..."))
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func ErrorView(error: String) -> some View {
|
||||||
|
Link(destination: URL(string: "solian://posts/shuffle")!) {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Image(systemName: "exclamationmark.triangle")
|
||||||
|
.font(.title3)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Text(NSLocalizedString("error", comment: "Error"))
|
||||||
|
.font(.headline)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(NSLocalizedString("openAppToRefresh", comment: "Open app to refresh"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Text(error)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.lineLimit(5)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func formatRelativeTime(_ date: Date) -> String {
|
||||||
|
let now = Date()
|
||||||
|
let interval = now.timeIntervalSince(date)
|
||||||
|
|
||||||
|
if interval < 60 {
|
||||||
|
return NSLocalizedString("justNow", comment: "Just now")
|
||||||
|
} else if interval < 3600 {
|
||||||
|
let minutes = Int(interval / 60)
|
||||||
|
return String(format: NSLocalizedString("minutesAgo", comment: "%d min ago"), minutes)
|
||||||
|
} else if interval < 86400 {
|
||||||
|
let hours = Int(interval / 3600)
|
||||||
|
return String(format: NSLocalizedString("hoursAgo", comment: "%d hr ago"), hours)
|
||||||
|
} else {
|
||||||
|
let days = Int(interval / 86400)
|
||||||
|
return String(format: NSLocalizedString("daysAgo", comment: "%d d ago"), days)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PostShuffleWidgetRootView: View {
|
||||||
|
var entry: PostShuffleProvider.Entry
|
||||||
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
ZStack {
|
||||||
|
PostShuffleWidgetEntryView(entry: entry)
|
||||||
|
|
||||||
|
if entry.post != nil {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
Image(colorScheme == .dark ? "CloudyLambDark" : "CloudyLamb")
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(
|
||||||
|
width: geometry.size.width * 0.9,
|
||||||
|
height: geometry.size.width * 0.9
|
||||||
|
)
|
||||||
|
.opacity(0.12)
|
||||||
|
.mask(
|
||||||
|
LinearGradient(
|
||||||
|
gradient: Gradient(colors: [
|
||||||
|
Color.white,
|
||||||
|
Color.white,
|
||||||
|
Color.clear
|
||||||
|
]),
|
||||||
|
startPoint: .topLeading,
|
||||||
|
endPoint: .bottomTrailing
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.position(
|
||||||
|
x: geometry.size.width * 0.9,
|
||||||
|
y: 20
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.allowsHitTesting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
.padding(.vertical, 8)
|
||||||
|
} else {
|
||||||
|
PostShuffleWidgetEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SolianPostShuffleWidget: Widget {
|
||||||
|
let kind: String = "SolianPostShuffleWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: PostShuffleProvider()) { entry in
|
||||||
|
PostShuffleWidgetRootView(entry: entry)
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Random Post")
|
||||||
|
.description("Discover a random post from the network")
|
||||||
|
.supportedFamilies(supportedFamilies)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var supportedFamilies: [WidgetFamily] {
|
||||||
|
return [.systemMedium, .systemLarge]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemMedium) {
|
||||||
|
SolianPostShuffleWidget()
|
||||||
|
} timeline: {
|
||||||
|
PostShuffleEntry(
|
||||||
|
date: .now,
|
||||||
|
post: SnPost(
|
||||||
|
id: "test-post-id",
|
||||||
|
title: "Hello World!",
|
||||||
|
description: "This is a test post description",
|
||||||
|
content: "This is a content of a test post. It can be longer and show more text in the widget.",
|
||||||
|
publisher: SnPostPublisher(
|
||||||
|
id: "publisher-1",
|
||||||
|
name: "Test Publisher",
|
||||||
|
nick: "Testy",
|
||||||
|
description: "A test publisher",
|
||||||
|
picture: nil
|
||||||
|
),
|
||||||
|
tags: [
|
||||||
|
SnPostTag(id: "tag-1", slug: "test", name: "Test"),
|
||||||
|
SnPostTag(id: "tag-2", slug: "example", name: "Example")
|
||||||
|
],
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
attachments: []
|
||||||
|
),
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemLarge) {
|
||||||
|
SolianPostShuffleWidget()
|
||||||
|
} timeline: {
|
||||||
|
PostShuffleEntry(
|
||||||
|
date: .now,
|
||||||
|
post: SnPost(
|
||||||
|
id: "test-post-id",
|
||||||
|
title: "Welcome to the Solar Network!",
|
||||||
|
description: "This is a test post description that is a bit longer to demonstrate the widget layout with various content types",
|
||||||
|
content: "This is content of a test post. It can be longer and show more text in the widget. The large widget should display more content and allow for better reading experience. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||||
|
publisher: SnPostPublisher(
|
||||||
|
id: "publisher-1",
|
||||||
|
name: "Test Publisher",
|
||||||
|
nick: "Testy McTestface",
|
||||||
|
description: "A test publisher",
|
||||||
|
picture: nil
|
||||||
|
),
|
||||||
|
tags: [
|
||||||
|
SnPostTag(id: "tag-1", slug: "test", name: "Test"),
|
||||||
|
SnPostTag(id: "tag-2", slug: "example", name: "Example"),
|
||||||
|
SnPostTag(id: "tag-3", slug: "widget", name: "Widget"),
|
||||||
|
SnPostTag(id: "tag-4", slug: "ios", name: "iOS")
|
||||||
|
],
|
||||||
|
createdAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
updatedAt: ISO8601DateFormatter().string(from: Date()),
|
||||||
|
attachments: [
|
||||||
|
SnCloudFile(id: "file-1", url: nil, thumbnail: nil, mimeType: "image/jpeg"),
|
||||||
|
SnCloudFile(id: "file-2", url: nil, thumbnail: nil, mimeType: "image/png")
|
||||||
|
]
|
||||||
|
),
|
||||||
|
error: nil,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
}
|
||||||
18
ios/SolianWidgetExtension/SolianWidgetExtensionBundle.swift
Normal file
18
ios/SolianWidgetExtension/SolianWidgetExtensionBundle.swift
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// SolianWidgetExtensionBundle.swift
|
||||||
|
// SolianWidgetExtension
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/3.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct SolianWidgetExtensionBundle: WidgetBundle {
|
||||||
|
var body: some Widget {
|
||||||
|
SolianCheckInWidget()
|
||||||
|
SolianNotificationWidget()
|
||||||
|
SolianPostShuffleWidget()
|
||||||
|
}
|
||||||
|
}
|
||||||
136
ios/SolianWidgetExtension/WidgetNetworking.swift
Normal file
136
ios/SolianWidgetExtension/WidgetNetworking.swift
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
//
|
||||||
|
// Networking.swift
|
||||||
|
// SolianWidgetExtensionExtension
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/4.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum RemoteError: Error {
|
||||||
|
case missingCredentials
|
||||||
|
case invalidURL
|
||||||
|
case invalidResponse
|
||||||
|
case httpError(Int)
|
||||||
|
case decodingError
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RemoteError: LocalizedError {
|
||||||
|
var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .missingCredentials:
|
||||||
|
return "Please open the app to sign in."
|
||||||
|
case .invalidURL:
|
||||||
|
return "Invalid server configuration."
|
||||||
|
case .invalidResponse:
|
||||||
|
return "Server returned an invalid response."
|
||||||
|
case .httpError(let code):
|
||||||
|
return "Server error (\(code))."
|
||||||
|
case .decodingError:
|
||||||
|
return "Failed to read server data."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TokenData: Codable {
|
||||||
|
let token: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetNetworkService {
|
||||||
|
private let appGroup = "group.solsynth.solian"
|
||||||
|
private let tokenKey = "flutter.dyn_user_tk"
|
||||||
|
private let urlKey = "flutter.app_server_url"
|
||||||
|
|
||||||
|
private lazy var session: URLSession = {
|
||||||
|
let configuration = URLSessionConfiguration.ephemeral
|
||||||
|
configuration.timeoutIntervalForRequest = 10.0
|
||||||
|
configuration.timeoutIntervalForResource = 10.0
|
||||||
|
configuration.waitsForConnectivity = false
|
||||||
|
return URLSession(configuration: configuration)
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var userDefaults: UserDefaults? {
|
||||||
|
UserDefaults(suiteName: appGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
var token: String? {
|
||||||
|
guard let tokenString = userDefaults?.string(forKey: tokenKey) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let data = tokenString.data(using: .utf8) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let tokenData = try JSONDecoder().decode(TokenData.self, from: data)
|
||||||
|
return tokenData.token
|
||||||
|
} catch {
|
||||||
|
print("[WidgetKit] Failed to decode token: \(error)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var baseURL: String {
|
||||||
|
return userDefaults?.string(forKey: urlKey) ?? "https://api.solian.app"
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRequest<T: Codable>(
|
||||||
|
path: String,
|
||||||
|
method: String = "GET",
|
||||||
|
headers: [String: String] = [:]
|
||||||
|
) async throws -> T? {
|
||||||
|
guard let token = token else {
|
||||||
|
throw RemoteError.missingCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let url = URL(string: "\(baseURL)\(path)") else {
|
||||||
|
throw RemoteError.invalidURL
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = method
|
||||||
|
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||||
|
|
||||||
|
for (key, value) in headers {
|
||||||
|
request.setValue(value, forHTTPHeaderField: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
request.timeoutInterval = 10.0
|
||||||
|
|
||||||
|
print("[WidgetKit] [Network] Requesting: \(baseURL)\(path)")
|
||||||
|
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
|
||||||
|
guard let httpResponse = response as? HTTPURLResponse else {
|
||||||
|
throw RemoteError.invalidResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[WidgetKit] [Network] Status: \(httpResponse.statusCode), Data length: \(data.count)")
|
||||||
|
|
||||||
|
if let jsonString = String(data: data, encoding: .utf8) {
|
||||||
|
print("[WidgetKit] [Network] Response: \(jsonString.prefix(500))")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch httpResponse.statusCode {
|
||||||
|
case 200...299:
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
do {
|
||||||
|
let result = try decoder.decode(T.self, from: data)
|
||||||
|
print("[WidgetKit] [Network] Successfully decoded response")
|
||||||
|
return result
|
||||||
|
} catch {
|
||||||
|
print("[WidgetKit] [Network] Decoding error: \(error.localizedDescription)")
|
||||||
|
print("[WidgetKit] [Network] Expected type: \(String(describing: T.self))")
|
||||||
|
throw RemoteError.decodingError
|
||||||
|
}
|
||||||
|
case 404:
|
||||||
|
print("[WidgetKit] [Network] Resource not found (404)")
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
print("[WidgetKit] [Network] HTTP Error: \(httpResponse.statusCode)")
|
||||||
|
throw RemoteError.httpError(httpResponse.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
ios/SolianWidgetExtension/en.lproj/Localizable.strings
Normal file
46
ios/SolianWidgetExtension/en.lproj/Localizable.strings
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/* Check In Level Names */
|
||||||
|
"checkInResultT0" = "Great Misfortune";
|
||||||
|
"checkInResultT1" = "Misfortune";
|
||||||
|
"checkInResultT2" = "Moderate";
|
||||||
|
"checkInResultT3" = "Fortune";
|
||||||
|
"checkInResultT4" = "Great Fortune";
|
||||||
|
"checkInResultT5" = "Special";
|
||||||
|
|
||||||
|
/* Widget UI Strings */
|
||||||
|
"checkIn" = "Check In";
|
||||||
|
"tapToCheckIn" = "Tap to check in today";
|
||||||
|
"error" = "Error";
|
||||||
|
"openAppToRefresh" = "Open app to refresh";
|
||||||
|
"loading" = "Loading...";
|
||||||
|
"rewardPoints" = "%d";
|
||||||
|
"rewardExperience" = "%d EXP";
|
||||||
|
"footer" = "Solian Check In";
|
||||||
|
|
||||||
|
/* Notable Day Strings */
|
||||||
|
"notableDayToday" = "%@ is today!";
|
||||||
|
"notableDayIs" = "%@ is %@";
|
||||||
|
"notableDayUpcoming" = "Upcoming";
|
||||||
|
"today" = "Today";
|
||||||
|
|
||||||
|
/* Notification Widget Strings */
|
||||||
|
"notifications" = "Notifications";
|
||||||
|
"noNotifications" = "No notifications yet";
|
||||||
|
"tapToViewAll" = "Tap to view all notifications";
|
||||||
|
"justNow" = "Just now";
|
||||||
|
"minutesAgo" = "%d min ago";
|
||||||
|
"hoursAgo" = "%d hr ago";
|
||||||
|
"daysAgo" = "%d d ago";
|
||||||
|
"pleaseSignIn" = "Please open the app to sign in.";
|
||||||
|
"invalidServerConfig" = "Invalid server configuration.";
|
||||||
|
"invalidResponse" = "Server returned an invalid response.";
|
||||||
|
"httpError" = "Server error (%d).";
|
||||||
|
"decodingError" = "Failed to read server data.";
|
||||||
|
"unreadNotifications" = "Notification(s) unread";
|
||||||
|
"noNotifications" = "No notifications";
|
||||||
|
"noUnreadNotifications" = "All notifications are read";
|
||||||
|
"unread" = "unread";
|
||||||
|
|
||||||
|
/* Post Shuffle Widget Strings */
|
||||||
|
"noPostsAvailable" = "No posts available";
|
||||||
|
"tapToRefresh" = "Tap to refresh";
|
||||||
|
"loadingPost" = "Loading post...";
|
||||||
41
ios/SolianWidgetExtension/es.lproj/Localizable.strings
Normal file
41
ios/SolianWidgetExtension/es.lproj/Localizable.strings
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* Check In Level Names */
|
||||||
|
"checkInResultT0" = "Gran Desventura";
|
||||||
|
"checkInResultT1" = "Desventura";
|
||||||
|
"checkInResultT2" = "Moderado";
|
||||||
|
"checkInResultT3" = "Buena Fortuna";
|
||||||
|
"checkInResultT4" = "Gran Fortuna";
|
||||||
|
"checkInResultT5" = "Especial";
|
||||||
|
|
||||||
|
/* Widget UI Strings */
|
||||||
|
"checkIn" = "Registrar";
|
||||||
|
"tapToCheckIn" = "Toca para registrar hoy";
|
||||||
|
"error" = "Error";
|
||||||
|
"openAppToRefresh" = "Abre la aplicación para actualizar";
|
||||||
|
"loading" = "Cargando...";
|
||||||
|
"rewardPoints" = "%d";
|
||||||
|
"rewardExperience" = "%d EXP";
|
||||||
|
"footer" = "Registro Solian";
|
||||||
|
|
||||||
|
/* Notable Day Strings */
|
||||||
|
"notableDayToday" = "%@ es hoy!";
|
||||||
|
"notableDayIs" = "%@ es %@";
|
||||||
|
"today" = "Hoy";
|
||||||
|
|
||||||
|
/* Notification Widget Strings */
|
||||||
|
"notifications" = "Notificaciones";
|
||||||
|
"noNotifications" = "Aún no hay notificaciones";
|
||||||
|
"tapToViewAll" = "Toca para ver todas las notificaciones";
|
||||||
|
"justNow" = "Ahora mismo";
|
||||||
|
"minutesAgo" = "hace %d min";
|
||||||
|
"hoursAgo" = "hace %d hr";
|
||||||
|
"daysAgo" = "hace %d días";
|
||||||
|
"pleaseSignIn" = "Por favor, abre la aplicación para iniciar sesión.";
|
||||||
|
"invalidServerConfig" = "Configuración del servidor no válida.";
|
||||||
|
"invalidResponse" = "El servidor devolvió una respuesta no válida.";
|
||||||
|
"httpError" = "Error del servidor (%d).";
|
||||||
|
"decodingError" = "Error al leer los datos del servidor.";
|
||||||
|
|
||||||
|
/* Post Shuffle Widget Strings */
|
||||||
|
"noPostsAvailable" = "No hay publicaciones disponibles";
|
||||||
|
"tapToRefresh" = "Toca para actualizar";
|
||||||
|
"loadingPost" = "Cargando publicación...";
|
||||||
41
ios/SolianWidgetExtension/ja.lproj/Localizable.strings
Normal file
41
ios/SolianWidgetExtension/ja.lproj/Localizable.strings
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* Check In Level Names */
|
||||||
|
"checkInResultT0" = "大凶";
|
||||||
|
"checkInResultT1" = "凶";
|
||||||
|
"checkInResultT2" = "中平";
|
||||||
|
"checkInResultT3" = "吉";
|
||||||
|
"checkInResultT4" = "大吉";
|
||||||
|
"checkInResultT5" = "特殊";
|
||||||
|
|
||||||
|
/* Widget UI Strings */
|
||||||
|
"checkIn" = "チェックイン";
|
||||||
|
"tapToCheckIn" = "タップして今日チェックイン";
|
||||||
|
"error" = "エラー";
|
||||||
|
"openAppToRefresh" = "アプリを開いて更新";
|
||||||
|
"loading" = "読み込み中...";
|
||||||
|
"rewardPoints" = "%d";
|
||||||
|
"rewardExperience" = "%d 経験値";
|
||||||
|
"footer" = "Solian チェックイン";
|
||||||
|
|
||||||
|
/* Notable Day Strings */
|
||||||
|
"notableDayToday" = "%@は今日です!";
|
||||||
|
"notableDayIs" = "%@は%@です";
|
||||||
|
"today" = "今日";
|
||||||
|
|
||||||
|
/* Notification Widget Strings */
|
||||||
|
"notifications" = "通知";
|
||||||
|
"noNotifications" = "まだ通知はありません";
|
||||||
|
"tapToViewAll" = "タップしてすべての通知を表示";
|
||||||
|
"justNow" = "たった今";
|
||||||
|
"minutesAgo" = "%d分前";
|
||||||
|
"hoursAgo" = "%d時間前";
|
||||||
|
"daysAgo" = "%d日前";
|
||||||
|
"pleaseSignIn" = "アプリを開いてサインインしてください。";
|
||||||
|
"invalidServerConfig" = "サーバー設定が無効です。";
|
||||||
|
"invalidResponse" = "サーバーから無効な応答が返されました。";
|
||||||
|
"httpError" = "サーバーエラー (%d)。";
|
||||||
|
"decodingError" = "サーバーデータの読み込みに失敗しました。";
|
||||||
|
|
||||||
|
/* Post Shuffle Widget Strings */
|
||||||
|
"noPostsAvailable" = "利用可能な投稿がありません";
|
||||||
|
"tapToRefresh" = "タップして更新";
|
||||||
|
"loadingPost" = "投稿を読み込み中...";
|
||||||
41
ios/SolianWidgetExtension/ko.lproj/Localizable.strings
Normal file
41
ios/SolianWidgetExtension/ko.lproj/Localizable.strings
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* Check In Level Names */
|
||||||
|
"checkInResultT0" = "대흉";
|
||||||
|
"checkInResultT1" = "흉";
|
||||||
|
"checkInResultT2" = "중평";
|
||||||
|
"checkInResultT3" = "길";
|
||||||
|
"checkInResultT4" = "대길";
|
||||||
|
"checkInResultT5" = "특수";
|
||||||
|
|
||||||
|
/* Widget UI Strings */
|
||||||
|
"checkIn" = "체크인";
|
||||||
|
"tapToCheckIn" = "탭하여 오늘 체크인";
|
||||||
|
"error" = "오류";
|
||||||
|
"openAppToRefresh" = "앱을 열어 새로고침";
|
||||||
|
"loading" = "로딩 중...";
|
||||||
|
"rewardPoints" = "%d";
|
||||||
|
"rewardExperience" = "%d 경험치";
|
||||||
|
"footer" = "Solian 체크인";
|
||||||
|
|
||||||
|
/* Notable Day Strings */
|
||||||
|
"notableDayToday" = "%@ 오늘입니다!";
|
||||||
|
"notableDayIs" = "%@ 은/는 %@";
|
||||||
|
"today" = "오늘";
|
||||||
|
|
||||||
|
/* Notification Widget Strings */
|
||||||
|
"notifications" = "알림";
|
||||||
|
"noNotifications" = "아직 알림이 없습니다";
|
||||||
|
"tapToViewAll" = "탭하여 모든 알림 보기";
|
||||||
|
"justNow" = "방금";
|
||||||
|
"minutesAgo" = "%d분 전";
|
||||||
|
"hoursAgo" = "%d시간 전";
|
||||||
|
"daysAgo" = "%d일 전";
|
||||||
|
"pleaseSignIn" = "앱을 열어 로그인하세요.";
|
||||||
|
"invalidServerConfig" = "서버 구성이 올바르지 않습니다.";
|
||||||
|
"invalidResponse" = "서버에서 잘못된 응답을 받았습니다.";
|
||||||
|
"httpError" = "서버 오류 (%d).";
|
||||||
|
"decodingError" = "서버 데이터 읽기에 실패했습니다.";
|
||||||
|
|
||||||
|
/* Post Shuffle Widget Strings */
|
||||||
|
"noPostsAvailable" = "사용 가능한 게시물이 없습니다";
|
||||||
|
"tapToRefresh" = "탭하여 새로고침";
|
||||||
|
"loadingPost" = "게시물 로딩 중...";
|
||||||
46
ios/SolianWidgetExtension/zh-Hans.lproj/Localizable.strings
Normal file
46
ios/SolianWidgetExtension/zh-Hans.lproj/Localizable.strings
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/* Check In Level Names */
|
||||||
|
"checkInResultT0" = "大凶";
|
||||||
|
"checkInResultT1" = "凶";
|
||||||
|
"checkInResultT2" = "中平";
|
||||||
|
"checkInResultT3" = "吉";
|
||||||
|
"checkInResultT4" = "大吉";
|
||||||
|
"checkInResultT5" = "特殊";
|
||||||
|
|
||||||
|
/* Widget UI Strings */
|
||||||
|
"checkIn" = "打卡";
|
||||||
|
"tapToCheckIn" = "点击今日打卡";
|
||||||
|
"error" = "错误";
|
||||||
|
"openAppToRefresh" = "打开应用以刷新";
|
||||||
|
"loading" = "加载中...";
|
||||||
|
"rewardPoints" = "%d";
|
||||||
|
"rewardExperience" = "%d 经验值";
|
||||||
|
"footer" = "Solian 签到";
|
||||||
|
|
||||||
|
/* Notable Day Strings */
|
||||||
|
"notableDayToday" = "%@是今天!";
|
||||||
|
"notableDayIs" = "%@ 是 %@";
|
||||||
|
"notableDayUpcoming" = "接下来";
|
||||||
|
"today" = "今天";
|
||||||
|
|
||||||
|
/* Notification Widget Strings */
|
||||||
|
"notifications" = "通知";
|
||||||
|
"noNotifications" = "还没有通知";
|
||||||
|
"tapToViewAll" = "点击查看所有通知";
|
||||||
|
"justNow" = "刚刚";
|
||||||
|
"minutesAgo" = "%d分钟前";
|
||||||
|
"hoursAgo" = "%d小时前";
|
||||||
|
"daysAgo" = "%d天前";
|
||||||
|
"pleaseSignIn" = "请打开应用登录。";
|
||||||
|
"invalidServerConfig" = "服务器配置无效。";
|
||||||
|
"invalidResponse" = "服务器返回了无效响应。";
|
||||||
|
"httpError" = "服务器错误 (%d)。";
|
||||||
|
"decodingError" = "读取服务器数据失败。";
|
||||||
|
"unreadNotifications" = "条通知未读";
|
||||||
|
"noNotifications" = "没有通知";
|
||||||
|
"noUnreadNotifications" = "没有未读通知";
|
||||||
|
"unread" = "未读";
|
||||||
|
|
||||||
|
/* Post Shuffle Widget Strings */
|
||||||
|
"noPostsAvailable" = "没有可用的帖子";
|
||||||
|
"tapToRefresh" = "点击刷新";
|
||||||
|
"loadingPost" = "加载帖子中...";
|
||||||
41
ios/SolianWidgetExtension/zh-Hant.lproj/Localizable.strings
Normal file
41
ios/SolianWidgetExtension/zh-Hant.lproj/Localizable.strings
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* Check In Level Names */
|
||||||
|
"checkInResultT0" = "大凶";
|
||||||
|
"checkInResultT1" = "凶";
|
||||||
|
"checkInResultT2" = "中平";
|
||||||
|
"checkInResultT3" = "吉";
|
||||||
|
"checkInResultT4" = "大吉";
|
||||||
|
"checkInResultT5" = "特殊";
|
||||||
|
|
||||||
|
/* Widget UI Strings */
|
||||||
|
"checkIn" = "打卡";
|
||||||
|
"tapToCheckIn" = "點擊今日打卡";
|
||||||
|
"error" = "錯誤";
|
||||||
|
"openAppToRefresh" = "打開應用以刷新";
|
||||||
|
"loading" = "載入中...";
|
||||||
|
"rewardPoints" = "%d";
|
||||||
|
"rewardExperience" = "%d 經驗值";
|
||||||
|
"footer" = "Solian 簽到";
|
||||||
|
|
||||||
|
/* Notable Day Strings */
|
||||||
|
"notableDayToday" = "%@是今天!";
|
||||||
|
"notableDayIs" = "%@ 是 %@";
|
||||||
|
"today" = "今天";
|
||||||
|
|
||||||
|
/* Notification Widget Strings */
|
||||||
|
"notifications" = "通知";
|
||||||
|
"noNotifications" = "還沒有通知";
|
||||||
|
"tapToViewAll" = "點擊查看所有通知";
|
||||||
|
"justNow" = "剛剛";
|
||||||
|
"minutesAgo" = "%d分鐘前";
|
||||||
|
"hoursAgo" = "%d小時前";
|
||||||
|
"daysAgo" = "%d天前";
|
||||||
|
"pleaseSignIn" = "請打開應用登錄。";
|
||||||
|
"invalidServerConfig" = "伺服器配置無效。";
|
||||||
|
"invalidResponse" = "伺服器返回了無效響應。";
|
||||||
|
"httpError" = "伺服器錯誤 (%d)。";
|
||||||
|
"decodingError" = "讀取伺服器數據失敗。";
|
||||||
|
|
||||||
|
/* Post Shuffle Widget Strings */
|
||||||
|
"noPostsAvailable" = "沒有可用的帖子";
|
||||||
|
"tapToRefresh" = "點擊刷新";
|
||||||
|
"loadingPost" = "載入帖子中...";
|
||||||
12
ios/SolianWidgetExtensionExtension.entitlements
Normal file
12
ios/SolianWidgetExtensionExtension.entitlements
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.solsynth.solian</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
135
lib/hooks/use_room_file_picker.dart
Normal file
135
lib/hooks/use_room_file_picker.dart
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:island/models/file.dart';
|
||||||
|
import 'package:island/widgets/chat/chat_link_attachments.dart';
|
||||||
|
|
||||||
|
class RoomFilePicker {
|
||||||
|
final List<UniversalFile> attachments;
|
||||||
|
final void Function(List<UniversalFile>) updateAttachments;
|
||||||
|
final Future<void> Function() pickPhotos;
|
||||||
|
final Future<void> Function() pickVideos;
|
||||||
|
final Future<void> Function() pickAudio;
|
||||||
|
final Future<void> Function() pickFiles;
|
||||||
|
final Future<void> Function() linkAttachment;
|
||||||
|
|
||||||
|
RoomFilePicker({
|
||||||
|
required this.attachments,
|
||||||
|
required this.updateAttachments,
|
||||||
|
required this.pickPhotos,
|
||||||
|
required this.pickVideos,
|
||||||
|
required this.pickAudio,
|
||||||
|
required this.pickFiles,
|
||||||
|
required this.linkAttachment,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomFilePicker useRoomFilePicker(
|
||||||
|
BuildContext context,
|
||||||
|
List<UniversalFile> currentAttachments,
|
||||||
|
Function(List<UniversalFile>) onAttachmentsChanged,
|
||||||
|
) {
|
||||||
|
final attachments = useState<List<UniversalFile>>(currentAttachments);
|
||||||
|
|
||||||
|
Future<void> pickPhotos() async {
|
||||||
|
final picker = ImagePicker();
|
||||||
|
final results = await picker.pickMultiImage();
|
||||||
|
if (results.isEmpty) return;
|
||||||
|
attachments.value = [
|
||||||
|
...attachments.value,
|
||||||
|
...results.map(
|
||||||
|
(xfile) => UniversalFile(data: xfile, type: UniversalFileType.image),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
onAttachmentsChanged(attachments.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pickVideos() async {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.video,
|
||||||
|
allowMultiple: true,
|
||||||
|
allowCompression: false,
|
||||||
|
);
|
||||||
|
if (result == null || result.count == 0) return;
|
||||||
|
attachments.value = [
|
||||||
|
...attachments.value,
|
||||||
|
...result.files.map(
|
||||||
|
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.video),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
onAttachmentsChanged(attachments.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pickAudio() async {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.audio,
|
||||||
|
allowMultiple: true,
|
||||||
|
allowCompression: false,
|
||||||
|
);
|
||||||
|
if (result == null || result.count == 0) return;
|
||||||
|
attachments.value = [
|
||||||
|
...attachments.value,
|
||||||
|
...result.files.map(
|
||||||
|
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.audio),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
onAttachmentsChanged(attachments.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pickFiles() async {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
allowMultiple: true,
|
||||||
|
allowCompression: false,
|
||||||
|
);
|
||||||
|
if (result == null || result.count == 0) return;
|
||||||
|
attachments.value = [
|
||||||
|
...attachments.value,
|
||||||
|
...result.files.map(
|
||||||
|
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.file),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
onAttachmentsChanged(attachments.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> linkAttachment() async {
|
||||||
|
final cloudFile = await showModalBottomSheet<SnCloudFile?>(
|
||||||
|
context: context,
|
||||||
|
useRootNavigator: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) => const ChatLinkAttachment(),
|
||||||
|
);
|
||||||
|
if (cloudFile == null) return;
|
||||||
|
|
||||||
|
attachments.value = [
|
||||||
|
...attachments.value,
|
||||||
|
UniversalFile(
|
||||||
|
data: cloudFile,
|
||||||
|
type: switch (cloudFile.mimeType?.split('/').firstOrNull) {
|
||||||
|
'image' => UniversalFileType.image,
|
||||||
|
'video' => UniversalFileType.video,
|
||||||
|
'audio' => UniversalFileType.audio,
|
||||||
|
_ => UniversalFileType.file,
|
||||||
|
},
|
||||||
|
isLink: true,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
onAttachmentsChanged(attachments.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateAttachments(List<UniversalFile> newAttachments) {
|
||||||
|
attachments.value = newAttachments;
|
||||||
|
onAttachmentsChanged(attachments.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RoomFilePicker(
|
||||||
|
attachments: attachments.value,
|
||||||
|
updateAttachments: updateAttachments,
|
||||||
|
pickPhotos: pickPhotos,
|
||||||
|
pickVideos: pickVideos,
|
||||||
|
pickAudio: pickAudio,
|
||||||
|
pickFiles: pickFiles,
|
||||||
|
linkAttachment: linkAttachment,
|
||||||
|
);
|
||||||
|
}
|
||||||
231
lib/hooks/use_room_input.dart
Normal file
231
lib/hooks/use_room_input.dart
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:island/models/file.dart';
|
||||||
|
import 'package:island/models/chat.dart';
|
||||||
|
import 'package:island/models/poll.dart';
|
||||||
|
import 'package:island/models/wallet.dart';
|
||||||
|
import 'package:island/pods/chat/chat_subscribe.dart';
|
||||||
|
import 'package:island/database/message.dart';
|
||||||
|
import 'package:island/pods/chat/messages_notifier.dart';
|
||||||
|
import 'package:island/widgets/chat/message_item.dart';
|
||||||
|
import 'package:pasteboard/pasteboard.dart';
|
||||||
|
|
||||||
|
class RoomInputManager {
|
||||||
|
final TextEditingController messageController;
|
||||||
|
final List<UniversalFile> attachments;
|
||||||
|
final Map<String, Map<int, double?>> attachmentProgress;
|
||||||
|
final SnChatMessage? messageEditingTo;
|
||||||
|
final SnChatMessage? messageReplyingTo;
|
||||||
|
final SnChatMessage? messageForwardingTo;
|
||||||
|
final SnPoll? selectedPoll;
|
||||||
|
final SnWalletFund? selectedFund;
|
||||||
|
final void Function(List<UniversalFile>) updateAttachments;
|
||||||
|
final void Function(String, double?) updateAttachmentProgress;
|
||||||
|
final void Function(SnChatMessage?) setEditingTo;
|
||||||
|
final void Function(SnChatMessage?) setReplyingTo;
|
||||||
|
final void Function(SnChatMessage?) setForwardingTo;
|
||||||
|
final void Function(SnPoll?) setPoll;
|
||||||
|
final void Function(SnWalletFund?) setFund;
|
||||||
|
final void Function() clear;
|
||||||
|
final void Function() clearAttachmentsOnly;
|
||||||
|
final Future<void> Function() handlePaste;
|
||||||
|
final void Function(WidgetRef ref) sendMessage;
|
||||||
|
final void Function(String action, LocalChatMessage message) onMessageAction;
|
||||||
|
|
||||||
|
RoomInputManager({
|
||||||
|
required this.messageController,
|
||||||
|
required this.attachments,
|
||||||
|
required this.attachmentProgress,
|
||||||
|
this.messageEditingTo,
|
||||||
|
this.messageReplyingTo,
|
||||||
|
this.messageForwardingTo,
|
||||||
|
this.selectedPoll,
|
||||||
|
this.selectedFund,
|
||||||
|
required this.updateAttachments,
|
||||||
|
required this.updateAttachmentProgress,
|
||||||
|
required this.setEditingTo,
|
||||||
|
required this.setReplyingTo,
|
||||||
|
required this.setForwardingTo,
|
||||||
|
required this.setPoll,
|
||||||
|
required this.setFund,
|
||||||
|
required this.clear,
|
||||||
|
required this.clearAttachmentsOnly,
|
||||||
|
required this.handlePaste,
|
||||||
|
required this.sendMessage,
|
||||||
|
required this.onMessageAction,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomInputManager useRoomInputManager(WidgetRef ref, String roomId) {
|
||||||
|
final messageController = useTextEditingController();
|
||||||
|
final attachments = useState<List<UniversalFile>>([]);
|
||||||
|
final attachmentProgress = useState<Map<String, Map<int, double?>>>({});
|
||||||
|
final messageEditingTo = useState<SnChatMessage?>(null);
|
||||||
|
final messageReplyingTo = useState<SnChatMessage?>(null);
|
||||||
|
final messageForwardingTo = useState<SnChatMessage?>(null);
|
||||||
|
final selectedPoll = useState<SnPoll?>(null);
|
||||||
|
final selectedFund = useState<SnWalletFund?>(null);
|
||||||
|
|
||||||
|
final chatSubscribeNotifier = ref.read(
|
||||||
|
chatSubscribeProvider(roomId).notifier,
|
||||||
|
);
|
||||||
|
final messagesNotifier = ref.read(messagesProvider(roomId).notifier);
|
||||||
|
|
||||||
|
void updateAttachments(List<UniversalFile> newAttachments) {
|
||||||
|
attachments.value = newAttachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateAttachmentProgress(String messageId, double? progress) {
|
||||||
|
attachmentProgress.value = {
|
||||||
|
...attachmentProgress.value,
|
||||||
|
messageId: {0: progress},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEditingTo(SnChatMessage? message) {
|
||||||
|
messageEditingTo.value = message;
|
||||||
|
if (message != null) {
|
||||||
|
messageController.text = message.content ?? '';
|
||||||
|
attachments.value = message.attachments
|
||||||
|
.map((e) => UniversalFile.fromAttachment(e))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setReplyingTo(SnChatMessage? message) {
|
||||||
|
messageReplyingTo.value = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setForwardingTo(SnChatMessage? message) {
|
||||||
|
messageForwardingTo.value = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPoll(SnPoll? poll) {
|
||||||
|
selectedPoll.value = poll;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFund(SnWalletFund? fund) {
|
||||||
|
selectedFund.value = fund;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
messageController.clear();
|
||||||
|
messageEditingTo.value = null;
|
||||||
|
messageReplyingTo.value = null;
|
||||||
|
messageForwardingTo.value = null;
|
||||||
|
selectedPoll.value = null;
|
||||||
|
selectedFund.value = null;
|
||||||
|
attachments.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearAttachmentsOnly() {
|
||||||
|
messageController.clear();
|
||||||
|
attachments.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTextChange() {
|
||||||
|
if (messageController.text.isNotEmpty) {
|
||||||
|
chatSubscribeNotifier.sendTypingStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
messageController.addListener(onTextChange);
|
||||||
|
return () => messageController.removeListener(onTextChange);
|
||||||
|
}, [messageController]);
|
||||||
|
|
||||||
|
Future<void> handlePaste() async {
|
||||||
|
final image = await Pasteboard.image;
|
||||||
|
if (image != null) {
|
||||||
|
final newAttachments = [
|
||||||
|
...attachments.value,
|
||||||
|
UniversalFile(
|
||||||
|
data: XFile.fromData(image, mimeType: "image/jpeg"),
|
||||||
|
type: UniversalFileType.image,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
attachments.value = newAttachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
final textData = await Clipboard.getData(Clipboard.kTextPlain);
|
||||||
|
if (textData != null && textData.text != null) {
|
||||||
|
final text = messageController.text;
|
||||||
|
final selection = messageController.selection;
|
||||||
|
final start = selection.start >= 0 ? selection.start : text.length;
|
||||||
|
final end = selection.end >= 0 ? selection.end : text.length;
|
||||||
|
final newText = text.replaceRange(start, end, textData.text!);
|
||||||
|
messageController.value = TextEditingValue(
|
||||||
|
text: newText,
|
||||||
|
selection: TextSelection.collapsed(
|
||||||
|
offset: start + textData.text!.length,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onMessageAction(String action, LocalChatMessage message) {
|
||||||
|
switch (action) {
|
||||||
|
case MessageItemAction.delete:
|
||||||
|
messagesNotifier.deleteMessage(message.id);
|
||||||
|
case MessageItemAction.edit:
|
||||||
|
setEditingTo(message.toRemoteMessage());
|
||||||
|
case MessageItemAction.forward:
|
||||||
|
setForwardingTo(message.toRemoteMessage());
|
||||||
|
case MessageItemAction.reply:
|
||||||
|
setReplyingTo(message.toRemoteMessage());
|
||||||
|
case MessageItemAction.resend:
|
||||||
|
messagesNotifier.retryMessage(message.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendMessage(WidgetRef ref) {
|
||||||
|
if (messageController.text.trim().isNotEmpty ||
|
||||||
|
attachments.value.isNotEmpty ||
|
||||||
|
selectedPoll.value != null ||
|
||||||
|
selectedFund.value != null) {
|
||||||
|
messagesNotifier.sendMessage(
|
||||||
|
ref,
|
||||||
|
messageController.text.trim(),
|
||||||
|
attachments.value,
|
||||||
|
poll: selectedPoll.value,
|
||||||
|
fund: selectedFund.value,
|
||||||
|
editingTo: messageEditingTo.value,
|
||||||
|
forwardingTo: messageForwardingTo.value,
|
||||||
|
replyingTo: messageReplyingTo.value,
|
||||||
|
onProgress: (messageId, progress) {
|
||||||
|
attachmentProgress.value = {
|
||||||
|
...attachmentProgress.value,
|
||||||
|
messageId: progress,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RoomInputManager(
|
||||||
|
messageController: messageController,
|
||||||
|
attachments: attachments.value,
|
||||||
|
attachmentProgress: attachmentProgress.value,
|
||||||
|
messageEditingTo: messageEditingTo.value,
|
||||||
|
messageReplyingTo: messageReplyingTo.value,
|
||||||
|
messageForwardingTo: messageForwardingTo.value,
|
||||||
|
selectedPoll: selectedPoll.value,
|
||||||
|
selectedFund: selectedFund.value,
|
||||||
|
updateAttachments: updateAttachments,
|
||||||
|
updateAttachmentProgress: updateAttachmentProgress,
|
||||||
|
setEditingTo: setEditingTo,
|
||||||
|
setReplyingTo: setReplyingTo,
|
||||||
|
setForwardingTo: setForwardingTo,
|
||||||
|
setPoll: setPoll,
|
||||||
|
setFund: setFund,
|
||||||
|
clear: clear,
|
||||||
|
clearAttachmentsOnly: clearAttachmentsOnly,
|
||||||
|
handlePaste: handlePaste,
|
||||||
|
sendMessage: sendMessage,
|
||||||
|
onMessageAction: onMessageAction,
|
||||||
|
);
|
||||||
|
}
|
||||||
127
lib/hooks/use_room_scroll.dart
Normal file
127
lib/hooks/use_room_scroll.dart
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/pods/chat/chat_room.dart';
|
||||||
|
import 'package:island/database/message.dart';
|
||||||
|
import 'package:island/pods/chat/messages_notifier.dart';
|
||||||
|
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||||
|
|
||||||
|
class RoomScrollManager {
|
||||||
|
final ScrollController scrollController;
|
||||||
|
final ListController listController;
|
||||||
|
final ValueNotifier<double> bottomGradientOpacity;
|
||||||
|
bool isScrollingToMessage;
|
||||||
|
final void Function({
|
||||||
|
required String messageId,
|
||||||
|
required List<LocalChatMessage> messageList,
|
||||||
|
})
|
||||||
|
scrollToMessage;
|
||||||
|
|
||||||
|
RoomScrollManager({
|
||||||
|
required this.scrollController,
|
||||||
|
required this.listController,
|
||||||
|
required this.bottomGradientOpacity,
|
||||||
|
required this.scrollToMessage,
|
||||||
|
this.isScrollingToMessage = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomScrollManager useRoomScrollManager(
|
||||||
|
WidgetRef ref,
|
||||||
|
String roomId,
|
||||||
|
Future<int> Function(String) jumpToMessage,
|
||||||
|
AsyncValue<List<LocalChatMessage>> messagesAsync,
|
||||||
|
) {
|
||||||
|
final scrollController = useScrollController();
|
||||||
|
final listController = useMemoized(() => ListController(), []);
|
||||||
|
final bottomGradientOpacity = useState(ValueNotifier<double>(0.0));
|
||||||
|
|
||||||
|
var isLoading = false;
|
||||||
|
var isScrollingToMessage = false;
|
||||||
|
final messagesNotifier = ref.read(messagesProvider(roomId).notifier);
|
||||||
|
final flashingMessagesNotifier = ref.read(flashingMessagesProvider.notifier);
|
||||||
|
|
||||||
|
void performScrollAnimation({required int index, required String messageId}) {
|
||||||
|
flashingMessagesNotifier.update((set) => set.union({messageId}));
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
try {
|
||||||
|
listController.animateToItem(
|
||||||
|
index: index,
|
||||||
|
scrollController: scrollController,
|
||||||
|
alignment: 0.5,
|
||||||
|
duration: (estimatedDistance) => Duration(
|
||||||
|
milliseconds: (estimatedDistance * 0.5).clamp(200, 800).toInt(),
|
||||||
|
),
|
||||||
|
curve: (estimatedDistance) => Curves.easeOutCubic,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future.delayed(const Duration(milliseconds: 800), () {
|
||||||
|
isScrollingToMessage = false;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
isScrollingToMessage = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrollToMessageWrapper({
|
||||||
|
required String messageId,
|
||||||
|
required List<LocalChatMessage> messageList,
|
||||||
|
}) {
|
||||||
|
if (isScrollingToMessage) return;
|
||||||
|
isScrollingToMessage = true;
|
||||||
|
|
||||||
|
final messageIndex = messageList.indexWhere((m) => m.id == messageId);
|
||||||
|
|
||||||
|
if (messageIndex == -1) {
|
||||||
|
jumpToMessage(messageId).then((index) {
|
||||||
|
if (index != -1) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
performScrollAnimation(index: index, messageId: messageId);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
isScrollingToMessage = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
performScrollAnimation(index: messageIndex, messageId: messageId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
void onScroll() {
|
||||||
|
messagesAsync.when(
|
||||||
|
data: (messageList) {
|
||||||
|
if (scrollController.position.pixels >=
|
||||||
|
scrollController.position.maxScrollExtent - 200) {
|
||||||
|
if (!isLoading) {
|
||||||
|
isLoading = true;
|
||||||
|
messagesNotifier.loadMore().then((_) => isLoading = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final pixels = scrollController.position.pixels;
|
||||||
|
bottomGradientOpacity.value.value = (pixels / 500.0).clamp(0.0, 1.0);
|
||||||
|
},
|
||||||
|
loading: () {},
|
||||||
|
error: (_, _) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollController.addListener(onScroll);
|
||||||
|
return () => scrollController.removeListener(onScroll);
|
||||||
|
}, [scrollController, messagesAsync]);
|
||||||
|
|
||||||
|
return RoomScrollManager(
|
||||||
|
scrollController: scrollController,
|
||||||
|
listController: listController,
|
||||||
|
bottomGradientOpacity: bottomGradientOpacity.value,
|
||||||
|
scrollToMessage: scrollToMessageWrapper,
|
||||||
|
isScrollingToMessage: isScrollingToMessage,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:croppy/croppy.dart';
|
import 'package:croppy/croppy.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart' hide TextDirection;
|
import 'package:easy_localization/easy_localization.dart' hide TextDirection;
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||||
@@ -20,7 +21,10 @@ import 'package:island/pods/userinfo.dart';
|
|||||||
import 'package:island/pods/websocket.dart';
|
import 'package:island/pods/websocket.dart';
|
||||||
import 'package:island/route.dart';
|
import 'package:island/route.dart';
|
||||||
import 'package:island/services/notify.dart';
|
import 'package:island/services/notify.dart';
|
||||||
|
import 'package:island/services/widget_sync_service.dart';
|
||||||
import 'package:island/services/timezone.dart';
|
import 'package:island/services/timezone.dart';
|
||||||
|
import 'package:island/services/app_intents.dart';
|
||||||
|
import 'package:island/services/quick_actions.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:relative_time/relative_time.dart';
|
import 'package:relative_time/relative_time.dart';
|
||||||
@@ -97,6 +101,28 @@ void main() async {
|
|||||||
talker.error("[SplashScreen] Failed to load timezone database... $err");
|
talker.error("[SplashScreen] Failed to load timezone database... $err");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
talker.info("[AppIntents] Initializing App Intents service...");
|
||||||
|
final appIntentsService = AppIntentsService();
|
||||||
|
await appIntentsService.initialize();
|
||||||
|
talker.info("[AppIntents] App Intents service is ready!");
|
||||||
|
} catch (err) {
|
||||||
|
talker.error(
|
||||||
|
"[AppIntents] Failed to initialize App Intents service... $err",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
talker.info("[QuickActions] Initializing Quick Actions service...");
|
||||||
|
final quickActionsService = QuickActionsService();
|
||||||
|
await quickActionsService.initialize();
|
||||||
|
talker.info("[QuickActions] Quick Actions service is ready!");
|
||||||
|
} catch (err) {
|
||||||
|
talker.error(
|
||||||
|
"[QuickActions] Failed to initialize Quick Actions service... $err",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
if (!kIsWeb && (Platform.isMacOS || Platform.isLinux || Platform.isWindows)) {
|
if (!kIsWeb && (Platform.isMacOS || Platform.isLinux || Platform.isWindows)) {
|
||||||
@@ -169,6 +195,12 @@ void main() async {
|
|||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
|
retry: (retryCount, error) {
|
||||||
|
if (error is DioException && error.response?.statusCode == 404) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return const Duration(milliseconds: 300);
|
||||||
|
},
|
||||||
observers: [
|
observers: [
|
||||||
TalkerRiverpodObserver(
|
TalkerRiverpodObserver(
|
||||||
talker: talker,
|
talker: talker,
|
||||||
@@ -282,6 +314,11 @@ class IslandApp extends HookConsumerWidget {
|
|||||||
ref.listen(websocketStateProvider, (_, state) {
|
ref.listen(websocketStateProvider, (_, state) {
|
||||||
talker.info('[WebSocket] $state');
|
talker.info('[WebSocket] $state');
|
||||||
});
|
});
|
||||||
|
ref.listen(userInfoProvider, (_, user) {
|
||||||
|
if (user.value != null) {
|
||||||
|
WidgetSyncService().syncToWidget();
|
||||||
|
}
|
||||||
|
});
|
||||||
Future(() {
|
Future(() {
|
||||||
userNotifier.fetchUser().then((_) {
|
userNotifier.fetchUser().then((_) {
|
||||||
final user = ref.watch(userInfoProvider);
|
final user = ref.watch(userInfoProvider);
|
||||||
|
|||||||
108
lib/models/activitypub.dart
Normal file
108
lib/models/activitypub.dart
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'activitypub.freezed.dart';
|
||||||
|
part 'activitypub.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnActivityPubInstance with _$SnActivityPubInstance {
|
||||||
|
const factory SnActivityPubInstance({
|
||||||
|
required String id,
|
||||||
|
required String domain,
|
||||||
|
String? name,
|
||||||
|
String? description,
|
||||||
|
String? software,
|
||||||
|
String? version,
|
||||||
|
String? iconUrl,
|
||||||
|
String? thumbnailUrl,
|
||||||
|
String? contactEmail,
|
||||||
|
String? contactAccountUsername,
|
||||||
|
int? activeUsers,
|
||||||
|
@Default(false) bool isBlocked,
|
||||||
|
@Default(false) bool isSilenced,
|
||||||
|
String? blockReason,
|
||||||
|
Map<String, dynamic>? metadata,
|
||||||
|
DateTime? lastFetchedAt,
|
||||||
|
DateTime? lastActivityAt,
|
||||||
|
DateTime? metadataFetchedAt,
|
||||||
|
}) = _SnActivityPubInstance;
|
||||||
|
|
||||||
|
factory SnActivityPubInstance.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnActivityPubInstanceFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnActivityPubUser with _$SnActivityPubUser {
|
||||||
|
const factory SnActivityPubUser({
|
||||||
|
required String actorUri,
|
||||||
|
required String username,
|
||||||
|
required String displayName,
|
||||||
|
required String bio,
|
||||||
|
required String avatarUrl,
|
||||||
|
required DateTime followedAt,
|
||||||
|
required bool isLocal,
|
||||||
|
required String instanceDomain,
|
||||||
|
}) = _SnActivityPubUser;
|
||||||
|
|
||||||
|
factory SnActivityPubUser.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnActivityPubUserFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnActivityPubActor with _$SnActivityPubActor {
|
||||||
|
const factory SnActivityPubActor({
|
||||||
|
required String id,
|
||||||
|
required String uri,
|
||||||
|
@Default('') String type,
|
||||||
|
String? displayName,
|
||||||
|
String? username,
|
||||||
|
String? summary,
|
||||||
|
String? inboxUri,
|
||||||
|
String? outboxUri,
|
||||||
|
String? followersUri,
|
||||||
|
String? followingUri,
|
||||||
|
String? featuredUri,
|
||||||
|
String? avatarUrl,
|
||||||
|
String? headerUrl,
|
||||||
|
String? publicKeyId,
|
||||||
|
String? publicKey,
|
||||||
|
@Default(false) bool isBot,
|
||||||
|
@Default(false) bool isLocked,
|
||||||
|
@Default(true) bool discoverable,
|
||||||
|
@Default(false) bool manuallyApprovesFollowers,
|
||||||
|
Map<String, dynamic>? endpoints,
|
||||||
|
Map<String, dynamic>? publicKeyData,
|
||||||
|
Map<String, dynamic>? metadata,
|
||||||
|
DateTime? lastFetchedAt,
|
||||||
|
DateTime? lastActivityAt,
|
||||||
|
required SnActivityPubInstance instance,
|
||||||
|
required String instanceId,
|
||||||
|
bool? isFollowing,
|
||||||
|
}) = _SnActivityPubActor;
|
||||||
|
|
||||||
|
factory SnActivityPubActor.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnActivityPubActorFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnActivityPubFollowResponse with _$SnActivityPubFollowResponse {
|
||||||
|
const factory SnActivityPubFollowResponse({
|
||||||
|
required bool success,
|
||||||
|
required String message,
|
||||||
|
}) = _SnActivityPubFollowResponse;
|
||||||
|
|
||||||
|
factory SnActivityPubFollowResponse.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnActivityPubFollowResponseFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnActorStatusResponse with _$SnActorStatusResponse {
|
||||||
|
const factory SnActorStatusResponse({
|
||||||
|
required bool enabled,
|
||||||
|
@Default(0) int followerCount,
|
||||||
|
SnActivityPubActor? actor,
|
||||||
|
String? actorUri,
|
||||||
|
}) = _SnActorStatusResponse;
|
||||||
|
|
||||||
|
factory SnActorStatusResponse.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnActorStatusResponseFromJson(json);
|
||||||
|
}
|
||||||
1535
lib/models/activitypub.freezed.dart
Normal file
1535
lib/models/activitypub.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
186
lib/models/activitypub.g.dart
Normal file
186
lib/models/activitypub.g.dart
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'activitypub.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_SnActivityPubInstance _$SnActivityPubInstanceFromJson(
|
||||||
|
Map<String, dynamic> json,
|
||||||
|
) => _SnActivityPubInstance(
|
||||||
|
id: json['id'] as String,
|
||||||
|
domain: json['domain'] as String,
|
||||||
|
name: json['name'] as String?,
|
||||||
|
description: json['description'] as String?,
|
||||||
|
software: json['software'] as String?,
|
||||||
|
version: json['version'] as String?,
|
||||||
|
iconUrl: json['icon_url'] as String?,
|
||||||
|
thumbnailUrl: json['thumbnail_url'] as String?,
|
||||||
|
contactEmail: json['contact_email'] as String?,
|
||||||
|
contactAccountUsername: json['contact_account_username'] as String?,
|
||||||
|
activeUsers: (json['active_users'] as num?)?.toInt(),
|
||||||
|
isBlocked: json['is_blocked'] as bool? ?? false,
|
||||||
|
isSilenced: json['is_silenced'] as bool? ?? false,
|
||||||
|
blockReason: json['block_reason'] as String?,
|
||||||
|
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||||
|
lastFetchedAt: json['last_fetched_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['last_fetched_at'] as String),
|
||||||
|
lastActivityAt: json['last_activity_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['last_activity_at'] as String),
|
||||||
|
metadataFetchedAt: json['metadata_fetched_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['metadata_fetched_at'] as String),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnActivityPubInstanceToJson(
|
||||||
|
_SnActivityPubInstance instance,
|
||||||
|
) => <String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'domain': instance.domain,
|
||||||
|
'name': instance.name,
|
||||||
|
'description': instance.description,
|
||||||
|
'software': instance.software,
|
||||||
|
'version': instance.version,
|
||||||
|
'icon_url': instance.iconUrl,
|
||||||
|
'thumbnail_url': instance.thumbnailUrl,
|
||||||
|
'contact_email': instance.contactEmail,
|
||||||
|
'contact_account_username': instance.contactAccountUsername,
|
||||||
|
'active_users': instance.activeUsers,
|
||||||
|
'is_blocked': instance.isBlocked,
|
||||||
|
'is_silenced': instance.isSilenced,
|
||||||
|
'block_reason': instance.blockReason,
|
||||||
|
'metadata': instance.metadata,
|
||||||
|
'last_fetched_at': instance.lastFetchedAt?.toIso8601String(),
|
||||||
|
'last_activity_at': instance.lastActivityAt?.toIso8601String(),
|
||||||
|
'metadata_fetched_at': instance.metadataFetchedAt?.toIso8601String(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_SnActivityPubUser _$SnActivityPubUserFromJson(Map<String, dynamic> json) =>
|
||||||
|
_SnActivityPubUser(
|
||||||
|
actorUri: json['actor_uri'] as String,
|
||||||
|
username: json['username'] as String,
|
||||||
|
displayName: json['display_name'] as String,
|
||||||
|
bio: json['bio'] as String,
|
||||||
|
avatarUrl: json['avatar_url'] as String,
|
||||||
|
followedAt: DateTime.parse(json['followed_at'] as String),
|
||||||
|
isLocal: json['is_local'] as bool,
|
||||||
|
instanceDomain: json['instance_domain'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnActivityPubUserToJson(_SnActivityPubUser instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'actor_uri': instance.actorUri,
|
||||||
|
'username': instance.username,
|
||||||
|
'display_name': instance.displayName,
|
||||||
|
'bio': instance.bio,
|
||||||
|
'avatar_url': instance.avatarUrl,
|
||||||
|
'followed_at': instance.followedAt.toIso8601String(),
|
||||||
|
'is_local': instance.isLocal,
|
||||||
|
'instance_domain': instance.instanceDomain,
|
||||||
|
};
|
||||||
|
|
||||||
|
_SnActivityPubActor _$SnActivityPubActorFromJson(Map<String, dynamic> json) =>
|
||||||
|
_SnActivityPubActor(
|
||||||
|
id: json['id'] as String,
|
||||||
|
uri: json['uri'] as String,
|
||||||
|
type: json['type'] as String? ?? '',
|
||||||
|
displayName: json['display_name'] as String?,
|
||||||
|
username: json['username'] as String?,
|
||||||
|
summary: json['summary'] as String?,
|
||||||
|
inboxUri: json['inbox_uri'] as String?,
|
||||||
|
outboxUri: json['outbox_uri'] as String?,
|
||||||
|
followersUri: json['followers_uri'] as String?,
|
||||||
|
followingUri: json['following_uri'] as String?,
|
||||||
|
featuredUri: json['featured_uri'] as String?,
|
||||||
|
avatarUrl: json['avatar_url'] as String?,
|
||||||
|
headerUrl: json['header_url'] as String?,
|
||||||
|
publicKeyId: json['public_key_id'] as String?,
|
||||||
|
publicKey: json['public_key'] as String?,
|
||||||
|
isBot: json['is_bot'] as bool? ?? false,
|
||||||
|
isLocked: json['is_locked'] as bool? ?? false,
|
||||||
|
discoverable: json['discoverable'] as bool? ?? true,
|
||||||
|
manuallyApprovesFollowers:
|
||||||
|
json['manually_approves_followers'] as bool? ?? false,
|
||||||
|
endpoints: json['endpoints'] as Map<String, dynamic>?,
|
||||||
|
publicKeyData: json['public_key_data'] as Map<String, dynamic>?,
|
||||||
|
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||||
|
lastFetchedAt: json['last_fetched_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['last_fetched_at'] as String),
|
||||||
|
lastActivityAt: json['last_activity_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['last_activity_at'] as String),
|
||||||
|
instance: SnActivityPubInstance.fromJson(
|
||||||
|
json['instance'] as Map<String, dynamic>,
|
||||||
|
),
|
||||||
|
instanceId: json['instance_id'] as String,
|
||||||
|
isFollowing: json['is_following'] as bool?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnActivityPubActorToJson(_SnActivityPubActor instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'uri': instance.uri,
|
||||||
|
'type': instance.type,
|
||||||
|
'display_name': instance.displayName,
|
||||||
|
'username': instance.username,
|
||||||
|
'summary': instance.summary,
|
||||||
|
'inbox_uri': instance.inboxUri,
|
||||||
|
'outbox_uri': instance.outboxUri,
|
||||||
|
'followers_uri': instance.followersUri,
|
||||||
|
'following_uri': instance.followingUri,
|
||||||
|
'featured_uri': instance.featuredUri,
|
||||||
|
'avatar_url': instance.avatarUrl,
|
||||||
|
'header_url': instance.headerUrl,
|
||||||
|
'public_key_id': instance.publicKeyId,
|
||||||
|
'public_key': instance.publicKey,
|
||||||
|
'is_bot': instance.isBot,
|
||||||
|
'is_locked': instance.isLocked,
|
||||||
|
'discoverable': instance.discoverable,
|
||||||
|
'manually_approves_followers': instance.manuallyApprovesFollowers,
|
||||||
|
'endpoints': instance.endpoints,
|
||||||
|
'public_key_data': instance.publicKeyData,
|
||||||
|
'metadata': instance.metadata,
|
||||||
|
'last_fetched_at': instance.lastFetchedAt?.toIso8601String(),
|
||||||
|
'last_activity_at': instance.lastActivityAt?.toIso8601String(),
|
||||||
|
'instance': instance.instance.toJson(),
|
||||||
|
'instance_id': instance.instanceId,
|
||||||
|
'is_following': instance.isFollowing,
|
||||||
|
};
|
||||||
|
|
||||||
|
_SnActivityPubFollowResponse _$SnActivityPubFollowResponseFromJson(
|
||||||
|
Map<String, dynamic> json,
|
||||||
|
) => _SnActivityPubFollowResponse(
|
||||||
|
success: json['success'] as bool,
|
||||||
|
message: json['message'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnActivityPubFollowResponseToJson(
|
||||||
|
_SnActivityPubFollowResponse instance,
|
||||||
|
) => <String, dynamic>{
|
||||||
|
'success': instance.success,
|
||||||
|
'message': instance.message,
|
||||||
|
};
|
||||||
|
|
||||||
|
_SnActorStatusResponse _$SnActorStatusResponseFromJson(
|
||||||
|
Map<String, dynamic> json,
|
||||||
|
) => _SnActorStatusResponse(
|
||||||
|
enabled: json['enabled'] as bool,
|
||||||
|
followerCount: (json['follower_count'] as num?)?.toInt() ?? 0,
|
||||||
|
actor: json['actor'] == null
|
||||||
|
? null
|
||||||
|
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
|
||||||
|
actorUri: json['actor_uri'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnActorStatusResponseToJson(
|
||||||
|
_SnActorStatusResponse instance,
|
||||||
|
) => <String, dynamic>{
|
||||||
|
'enabled': instance.enabled,
|
||||||
|
'follower_count': instance.followerCount,
|
||||||
|
'actor': instance.actor?.toJson(),
|
||||||
|
'actor_uri': instance.actorUri,
|
||||||
|
};
|
||||||
@@ -8,7 +8,7 @@ sealed class SnScrappedLink with _$SnScrappedLink {
|
|||||||
const factory SnScrappedLink({
|
const factory SnScrappedLink({
|
||||||
required String type,
|
required String type,
|
||||||
required String url,
|
required String url,
|
||||||
required String title,
|
required String? title,
|
||||||
required String? description,
|
required String? description,
|
||||||
required String? imageUrl,
|
required String? imageUrl,
|
||||||
required String? faviconUrl,
|
required String? faviconUrl,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnScrappedLink {
|
mixin _$SnScrappedLink {
|
||||||
|
|
||||||
String get type; String get url; String get title; String? get description; String? get imageUrl; String? get faviconUrl; String? get siteName; String? get contentType; String? get author; DateTime? get publishedDate;
|
String get type; String get url; String? get title; String? get description; String? get imageUrl; String? get faviconUrl; String? get siteName; String? get contentType; String? get author; DateTime? get publishedDate;
|
||||||
/// Create a copy of SnScrappedLink
|
/// Create a copy of SnScrappedLink
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -48,7 +48,7 @@ abstract mixin class $SnScrappedLinkCopyWith<$Res> {
|
|||||||
factory $SnScrappedLinkCopyWith(SnScrappedLink value, $Res Function(SnScrappedLink) _then) = _$SnScrappedLinkCopyWithImpl;
|
factory $SnScrappedLinkCopyWith(SnScrappedLink value, $Res Function(SnScrappedLink) _then) = _$SnScrappedLinkCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
|
String type, String url, String? title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -65,12 +65,12 @@ class _$SnScrappedLinkCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnScrappedLink
|
/// Create a copy of SnScrappedLink
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,Object? title = freezed,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||||
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||||
as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||||
as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
|
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -159,7 +159,7 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String type, String url, String? title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnScrappedLink() when $default != null:
|
case _SnScrappedLink() when $default != null:
|
||||||
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
|
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
|
||||||
@@ -180,7 +180,7 @@ return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUr
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String type, String url, String? title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnScrappedLink():
|
case _SnScrappedLink():
|
||||||
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);}
|
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);}
|
||||||
@@ -197,7 +197,7 @@ return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUr
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String type, String url, String? title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnScrappedLink() when $default != null:
|
case _SnScrappedLink() when $default != null:
|
||||||
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
|
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
|
||||||
@@ -217,7 +217,7 @@ class _SnScrappedLink implements SnScrappedLink {
|
|||||||
|
|
||||||
@override final String type;
|
@override final String type;
|
||||||
@override final String url;
|
@override final String url;
|
||||||
@override final String title;
|
@override final String? title;
|
||||||
@override final String? description;
|
@override final String? description;
|
||||||
@override final String? imageUrl;
|
@override final String? imageUrl;
|
||||||
@override final String? faviconUrl;
|
@override final String? faviconUrl;
|
||||||
@@ -259,7 +259,7 @@ abstract mixin class _$SnScrappedLinkCopyWith<$Res> implements $SnScrappedLinkCo
|
|||||||
factory _$SnScrappedLinkCopyWith(_SnScrappedLink value, $Res Function(_SnScrappedLink) _then) = __$SnScrappedLinkCopyWithImpl;
|
factory _$SnScrappedLinkCopyWith(_SnScrappedLink value, $Res Function(_SnScrappedLink) _then) = __$SnScrappedLinkCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
|
String type, String url, String? title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -276,12 +276,12 @@ class __$SnScrappedLinkCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnScrappedLink
|
/// Create a copy of SnScrappedLink
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,Object? title = freezed,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
||||||
return _then(_SnScrappedLink(
|
return _then(_SnScrappedLink(
|
||||||
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||||
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||||
as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||||
as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
|
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ _SnScrappedLink _$SnScrappedLinkFromJson(Map<String, dynamic> json) =>
|
|||||||
_SnScrappedLink(
|
_SnScrappedLink(
|
||||||
type: json['type'] as String,
|
type: json['type'] as String,
|
||||||
url: json['url'] as String,
|
url: json['url'] as String,
|
||||||
title: json['title'] as String,
|
title: json['title'] as String?,
|
||||||
description: json['description'] as String?,
|
description: json['description'] as String?,
|
||||||
imageUrl: json['image_url'] as String?,
|
imageUrl: json['image_url'] as String?,
|
||||||
faviconUrl: json['favicon_url'] as String?,
|
faviconUrl: json['favicon_url'] as String?,
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ sealed class SnCloudFile with _$SnCloudFile {
|
|||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
required DateTime updatedAt,
|
required DateTime updatedAt,
|
||||||
required DateTime? deletedAt,
|
required DateTime? deletedAt,
|
||||||
|
String? url,
|
||||||
}) = _SnCloudFile;
|
}) = _SnCloudFile;
|
||||||
|
|
||||||
factory SnCloudFile.fromJson(Map<String, dynamic> json) =>
|
factory SnCloudFile.fromJson(Map<String, dynamic> json) =>
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ as String?,
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnCloudFile {
|
mixin _$SnCloudFile {
|
||||||
|
|
||||||
String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String? get url;
|
||||||
/// Create a copy of SnCloudFile
|
/// Create a copy of SnCloudFile
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -294,16 +294,16 @@ $SnCloudFileCopyWith<SnCloudFile> get copyWith => _$SnCloudFileCopyWithImpl<SnCl
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt);
|
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ abstract mixin class $SnCloudFileCopyWith<$Res> {
|
|||||||
factory $SnCloudFileCopyWith(SnCloudFile value, $Res Function(SnCloudFile) _then) = _$SnCloudFileCopyWithImpl;
|
factory $SnCloudFileCopyWith(SnCloudFile value, $Res Function(SnCloudFile) _then) = _$SnCloudFileCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ class _$SnCloudFileCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnCloudFile
|
/// Create a copy of SnCloudFile
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -348,7 +348,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
|
|||||||
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as String?,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,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,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
/// Create a copy of SnCloudFile
|
/// Create a copy of SnCloudFile
|
||||||
@@ -442,10 +443,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnCloudFile() when $default != null:
|
case _SnCloudFile() when $default != null:
|
||||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -463,10 +464,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnCloudFile():
|
case _SnCloudFile():
|
||||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -480,10 +481,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnCloudFile() when $default != null:
|
case _SnCloudFile() when $default != null:
|
||||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -495,7 +496,7 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnCloudFile implements SnCloudFile {
|
class _SnCloudFile implements SnCloudFile {
|
||||||
const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks;
|
const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt, this.url}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks;
|
||||||
factory _SnCloudFile.fromJson(Map<String, dynamic> json) => _$SnCloudFileFromJson(json);
|
factory _SnCloudFile.fromJson(Map<String, dynamic> json) => _$SnCloudFileFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@@ -535,6 +536,7 @@ class _SnCloudFile implements SnCloudFile {
|
|||||||
@override final DateTime createdAt;
|
@override final DateTime createdAt;
|
||||||
@override final DateTime updatedAt;
|
@override final DateTime updatedAt;
|
||||||
@override final DateTime? deletedAt;
|
@override final DateTime? deletedAt;
|
||||||
|
@override final String? url;
|
||||||
|
|
||||||
/// Create a copy of SnCloudFile
|
/// Create a copy of SnCloudFile
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@@ -549,16 +551,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt);
|
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -569,7 +571,7 @@ abstract mixin class _$SnCloudFileCopyWith<$Res> implements $SnCloudFileCopyWith
|
|||||||
factory _$SnCloudFileCopyWith(_SnCloudFile value, $Res Function(_SnCloudFile) _then) = __$SnCloudFileCopyWithImpl;
|
factory _$SnCloudFileCopyWith(_SnCloudFile value, $Res Function(_SnCloudFile) _then) = __$SnCloudFileCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -586,7 +588,7 @@ class __$SnCloudFileCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnCloudFile
|
/// Create a copy of SnCloudFile
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
|
||||||
return _then(_SnCloudFile(
|
return _then(_SnCloudFile(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -603,7 +605,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
|
|||||||
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as String?,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,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,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ _SnCloudFile _$SnCloudFileFromJson(Map<String, dynamic> json) => _SnCloudFile(
|
|||||||
deletedAt: json['deleted_at'] == null
|
deletedAt: json['deleted_at'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json['deleted_at'] as String),
|
: DateTime.parse(json['deleted_at'] as String),
|
||||||
|
url: json['url'] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
|
Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
|
||||||
@@ -74,6 +75,7 @@ Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
|
|||||||
'created_at': instance.createdAt.toIso8601String(),
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
|
'url': instance.url,
|
||||||
};
|
};
|
||||||
|
|
||||||
_SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) =>
|
_SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) =>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/models/account.dart';
|
||||||
|
import 'package:island/models/activitypub.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';
|
||||||
@@ -39,8 +40,14 @@ sealed class SnPost with _$SnPost {
|
|||||||
SnPost? forwardedPost,
|
SnPost? forwardedPost,
|
||||||
String? realmId,
|
String? realmId,
|
||||||
SnRealm? realm,
|
SnRealm? realm,
|
||||||
|
String? publisherId,
|
||||||
|
SnPublisher? publisher,
|
||||||
|
String? actorid,
|
||||||
|
SnActivityPubActor? actor,
|
||||||
|
String? fediverseUri,
|
||||||
|
int? fediverseType,
|
||||||
|
@Default(0) int contentType,
|
||||||
@Default([]) List<SnCloudFile> attachments,
|
@Default([]) List<SnCloudFile> attachments,
|
||||||
required SnPublisher publisher,
|
|
||||||
@Default({}) Map<String, int> reactionsCount,
|
@Default({}) Map<String, int> reactionsCount,
|
||||||
@Default({}) Map<String, bool> reactionsMade,
|
@Default({}) Map<String, bool> reactionsMade,
|
||||||
@Default([]) List<dynamic> reactions,
|
@Default([]) List<dynamic> reactions,
|
||||||
@@ -155,10 +162,12 @@ sealed class SnPostReaction with _$SnPostReaction {
|
|||||||
required String symbol,
|
required String symbol,
|
||||||
required int attitude,
|
required int attitude,
|
||||||
required String postId,
|
required String postId,
|
||||||
required String accountId,
|
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
required DateTime updatedAt,
|
required DateTime updatedAt,
|
||||||
@Default(null) SnAccount? account,
|
String? actorId,
|
||||||
|
SnActivityPubActor? actor,
|
||||||
|
String? accountId,
|
||||||
|
SnAccount? account,
|
||||||
DateTime? deletedAt,
|
DateTime? deletedAt,
|
||||||
}) = _SnPostReaction;
|
}) = _SnPostReaction;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnPost {
|
mixin _$SnPost {
|
||||||
|
|
||||||
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; SnPostEmbedView? get embedView; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int get awardedScore; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List<SnCloudFile> get attachments; SnPublisher get publisher; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; List<SnPostFeaturedRecord> get featuredRecords; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get repliedGone; bool get forwardedGone; bool get isTruncated;
|
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; SnPostEmbedView? get embedView; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int get awardedScore; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; String? get publisherId; SnPublisher? get publisher; String? get actorid; SnActivityPubActor? get actor; String? get fediverseUri; int? get fediverseType; int get contentType; List<SnCloudFile> get attachments; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; List<SnPostFeaturedRecord> get featuredRecords; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get repliedGone; bool get forwardedGone; bool get isTruncated;
|
||||||
/// Create a copy of SnPost
|
/// Create a copy of SnPost
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -28,16 +28,16 @@ $SnPostCopyWith<SnPost> get copyWith => _$SnPostCopyWithImpl<SnPost>(this as SnP
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&const DeepCollectionEquality().equals(other.featuredRecords, featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.actorid, actorid) || other.actorid == actorid)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.fediverseUri, fediverseUri) || other.fediverseUri == fediverseUri)&&(identical(other.fediverseType, fediverseType) || other.fediverseType == fediverseType)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&const DeepCollectionEquality().equals(other.featuredRecords, featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),const DeepCollectionEquality().hash(featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,publisherId,publisher,actorid,actor,fediverseUri,fediverseType,contentType,const DeepCollectionEquality().hash(attachments),const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),const DeepCollectionEquality().hash(featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, publisherId: $publisherId, publisher: $publisher, actorid: $actorid, actor: $actor, fediverseUri: $fediverseUri, fediverseType: $fediverseType, contentType: $contentType, attachments: $attachments, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -48,11 +48,11 @@ abstract mixin class $SnPostCopyWith<$Res> {
|
|||||||
factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
|
factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$SnPostEmbedViewCopyWith<$Res>? get embedView;$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res> get publisher;
|
$SnPostEmbedViewCopyWith<$Res>? get embedView;$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res>? get publisher;$SnActivityPubActorCopyWith<$Res>? get actor;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnPost
|
/// Create a copy of SnPost
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? publisherId = freezed,Object? publisher = freezed,Object? actorid = freezed,Object? actor = freezed,Object? fediverseUri = freezed,Object? fediverseType = freezed,Object? contentType = null,Object? attachments = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -94,9 +94,15 @@ as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId :
|
|||||||
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
||||||
as SnRealm?,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
|
as SnRealm?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||||
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
as String?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPublisher,reactionsCount: null == reactionsCount ? _self.reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
as SnPublisher?,actorid: freezed == actorid ? _self.actorid : actorid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnActivityPubActor?,fediverseUri: freezed == fediverseUri ? _self.fediverseUri : fediverseUri // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,fediverseType: freezed == fediverseType ? _self.fediverseType : fediverseType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,contentType: null == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<SnCloudFile>,reactionsCount: null == reactionsCount ? _self.reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||||
as Map<String, int>,reactionsMade: null == reactionsMade ? _self.reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
as Map<String, int>,reactionsMade: null == reactionsMade ? _self.reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
||||||
as Map<String, bool>,reactions: null == reactions ? _self.reactions : reactions // ignore: cast_nullable_to_non_nullable
|
as Map<String, bool>,reactions: null == reactions ? _self.reactions : reactions // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,tags: null == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,tags: null == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -176,11 +182,26 @@ $SnRealmCopyWith<$Res>? get realm {
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SnPublisherCopyWith<$Res> get publisher {
|
$SnPublisherCopyWith<$Res>? get publisher {
|
||||||
|
if (_self.publisher == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
|
return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) {
|
||||||
return _then(_self.copyWith(publisher: value));
|
return _then(_self.copyWith(publisher: value));
|
||||||
});
|
});
|
||||||
|
}/// Create a copy of SnPost
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||||
|
if (_self.actor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||||
|
return _then(_self.copyWith(actor: value));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,10 +281,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPost() when $default != null:
|
case _SnPost() when $default != null:
|
||||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -281,10 +302,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPost():
|
case _SnPost():
|
||||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);}
|
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -298,10 +319,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPost() when $default != null:
|
case _SnPost() when $default != null:
|
||||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -313,7 +334,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
|||||||
@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.slug, this.type = 0, final Map<String, dynamic>? meta, this.embedView, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.awardedScore = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final List<SnCloudFile> attachments = const [], required this.publisher, final Map<String, int> reactionsCount = const {}, final Map<String, bool> reactionsMade = const {}, final List<dynamic> reactions = const [], final List<SnPostTag> tags = const [], final List<SnPostCategory> categories = const [], final List<dynamic> collections = const [], final List<SnPostFeaturedRecord> featuredRecords = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.repliedGone = false, this.forwardedGone = false, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections,_featuredRecords = featuredRecords;
|
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.embedView, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.awardedScore = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, this.publisherId, this.publisher, this.actorid, this.actor, this.fediverseUri, this.fediverseType, this.contentType = 0, final List<SnCloudFile> attachments = const [], final Map<String, int> reactionsCount = const {}, final Map<String, bool> reactionsMade = const {}, final List<dynamic> reactions = const [], final List<SnPostTag> tags = const [], final List<SnPostCategory> categories = const [], final List<dynamic> collections = const [], final List<SnPostFeaturedRecord> featuredRecords = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.repliedGone = false, this.forwardedGone = false, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections,_featuredRecords = featuredRecords;
|
||||||
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;
|
||||||
@@ -351,6 +372,13 @@ class _SnPost implements SnPost {
|
|||||||
@override final SnPost? forwardedPost;
|
@override final SnPost? forwardedPost;
|
||||||
@override final String? realmId;
|
@override final String? realmId;
|
||||||
@override final SnRealm? realm;
|
@override final SnRealm? realm;
|
||||||
|
@override final String? publisherId;
|
||||||
|
@override final SnPublisher? publisher;
|
||||||
|
@override final String? actorid;
|
||||||
|
@override final SnActivityPubActor? actor;
|
||||||
|
@override final String? fediverseUri;
|
||||||
|
@override final int? fediverseType;
|
||||||
|
@override@JsonKey() final int contentType;
|
||||||
final List<SnCloudFile> _attachments;
|
final List<SnCloudFile> _attachments;
|
||||||
@override@JsonKey() List<SnCloudFile> get attachments {
|
@override@JsonKey() List<SnCloudFile> get attachments {
|
||||||
if (_attachments is EqualUnmodifiableListView) return _attachments;
|
if (_attachments is EqualUnmodifiableListView) return _attachments;
|
||||||
@@ -358,7 +386,6 @@ class _SnPost implements SnPost {
|
|||||||
return EqualUnmodifiableListView(_attachments);
|
return EqualUnmodifiableListView(_attachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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;
|
||||||
@@ -428,16 +455,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&const DeepCollectionEquality().equals(other._featuredRecords, _featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.actorid, actorid) || other.actorid == actorid)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.fediverseUri, fediverseUri) || other.fediverseUri == fediverseUri)&&(identical(other.fediverseType, fediverseType) || other.fediverseType == fediverseType)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&const DeepCollectionEquality().equals(other._featuredRecords, _featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),const DeepCollectionEquality().hash(_featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,publisherId,publisher,actorid,actor,fediverseUri,fediverseType,contentType,const DeepCollectionEquality().hash(_attachments),const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),const DeepCollectionEquality().hash(_featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, publisherId: $publisherId, publisher: $publisher, actorid: $actorid, actor: $actor, fediverseUri: $fediverseUri, fediverseType: $fediverseType, contentType: $contentType, attachments: $attachments, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -448,11 +475,11 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> {
|
|||||||
factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
|
factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@override $SnPostEmbedViewCopyWith<$Res>? get embedView;@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnRealmCopyWith<$Res>? get realm;@override $SnPublisherCopyWith<$Res> get publisher;
|
@override $SnPostEmbedViewCopyWith<$Res>? get embedView;@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnRealmCopyWith<$Res>? get realm;@override $SnPublisherCopyWith<$Res>? get publisher;@override $SnActivityPubActorCopyWith<$Res>? get actor;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -465,7 +492,7 @@ class __$SnPostCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnPost
|
/// Create a copy of SnPost
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? publisherId = freezed,Object? publisher = freezed,Object? actorid = freezed,Object? actor = freezed,Object? fediverseUri = freezed,Object? fediverseType = freezed,Object? contentType = null,Object? attachments = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
||||||
return _then(_SnPost(
|
return _then(_SnPost(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -494,9 +521,15 @@ as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId :
|
|||||||
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
||||||
as SnRealm?,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
|
as SnRealm?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||||
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
as String?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPublisher,reactionsCount: null == reactionsCount ? _self._reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
as SnPublisher?,actorid: freezed == actorid ? _self.actorid : actorid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnActivityPubActor?,fediverseUri: freezed == fediverseUri ? _self.fediverseUri : fediverseUri // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,fediverseType: freezed == fediverseType ? _self.fediverseType : fediverseType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,contentType: null == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<SnCloudFile>,reactionsCount: null == reactionsCount ? _self._reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||||
as Map<String, int>,reactionsMade: null == reactionsMade ? _self._reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
as Map<String, int>,reactionsMade: null == reactionsMade ? _self._reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
||||||
as Map<String, bool>,reactions: null == reactions ? _self._reactions : reactions // ignore: cast_nullable_to_non_nullable
|
as Map<String, bool>,reactions: null == reactions ? _self._reactions : reactions // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,tags: null == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,tags: null == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -577,11 +610,26 @@ $SnRealmCopyWith<$Res>? get realm {
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SnPublisherCopyWith<$Res> get publisher {
|
$SnPublisherCopyWith<$Res>? get publisher {
|
||||||
|
if (_self.publisher == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
|
return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) {
|
||||||
return _then(_self.copyWith(publisher: value));
|
return _then(_self.copyWith(publisher: value));
|
||||||
});
|
});
|
||||||
|
}/// Create a copy of SnPost
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||||
|
if (_self.actor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||||
|
return _then(_self.copyWith(actor: value));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1937,7 +1985,7 @@ as DateTime?,
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnPostReaction {
|
mixin _$SnPostReaction {
|
||||||
|
|
||||||
String get id; String get symbol; int get attitude; String get postId; String get accountId; DateTime get createdAt; DateTime get updatedAt; SnAccount? get account; DateTime? get deletedAt;
|
String get id; String get symbol; int get attitude; String get postId; DateTime get createdAt; DateTime get updatedAt; String? get actorId; SnActivityPubActor? get actor; String? get accountId; SnAccount? get account; DateTime? get deletedAt;
|
||||||
/// Create a copy of SnPostReaction
|
/// Create a copy of SnPostReaction
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -1950,16 +1998,16 @@ $SnPostReactionCopyWith<SnPostReaction> get copyWith => _$SnPostReactionCopyWith
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.actorId, actorId) || other.actorId == actorId)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,accountId,createdAt,updatedAt,account,deletedAt);
|
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,createdAt,updatedAt,actorId,actor,accountId,account,deletedAt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, account: $account, deletedAt: $deletedAt)';
|
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, createdAt: $createdAt, updatedAt: $updatedAt, actorId: $actorId, actor: $actor, accountId: $accountId, account: $account, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1970,11 +2018,11 @@ abstract mixin class $SnPostReactionCopyWith<$Res> {
|
|||||||
factory $SnPostReactionCopyWith(SnPostReaction value, $Res Function(SnPostReaction) _then) = _$SnPostReactionCopyWithImpl;
|
factory $SnPostReactionCopyWith(SnPostReaction value, $Res Function(SnPostReaction) _then) = _$SnPostReactionCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt
|
String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$SnAccountCopyWith<$Res>? get account;
|
$SnActivityPubActorCopyWith<$Res>? get actor;$SnAccountCopyWith<$Res>? get account;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -1987,16 +2035,18 @@ class _$SnPostReactionCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnPostReaction
|
/// Create a copy of SnPostReaction
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? account = freezed,Object? deletedAt = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? createdAt = null,Object? updatedAt = null,Object? actorId = freezed,Object? actor = freezed,Object? accountId = freezed,Object? account = freezed,Object? deletedAt = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
|
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
|
||||||
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
|
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
|
||||||
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
|
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as String,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,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
as DateTime,actorId: freezed == actorId ? _self.actorId : actorId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnActivityPubActor?,accountId: freezed == 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?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
as SnAccount?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,
|
||||||
));
|
));
|
||||||
@@ -2005,6 +2055,18 @@ as DateTime?,
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||||
|
if (_self.actor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||||
|
return _then(_self.copyWith(actor: value));
|
||||||
|
});
|
||||||
|
}/// Create a copy of SnPostReaction
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
$SnAccountCopyWith<$Res>? get account {
|
$SnAccountCopyWith<$Res>? get account {
|
||||||
if (_self.account == null) {
|
if (_self.account == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -2092,10 +2154,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPostReaction() when $default != null:
|
case _SnPostReaction() when $default != null:
|
||||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);case _:
|
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2113,10 +2175,10 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPostReaction():
|
case _SnPostReaction():
|
||||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);}
|
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -2130,10 +2192,10 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPostReaction() when $default != null:
|
case _SnPostReaction() when $default != null:
|
||||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);case _:
|
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2145,17 +2207,19 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnPostReaction implements SnPostReaction {
|
class _SnPostReaction implements SnPostReaction {
|
||||||
const _SnPostReaction({required this.id, required this.symbol, required this.attitude, required this.postId, required this.accountId, required this.createdAt, required this.updatedAt, this.account = null, this.deletedAt});
|
const _SnPostReaction({required this.id, required this.symbol, required this.attitude, required this.postId, required this.createdAt, required this.updatedAt, this.actorId, this.actor, this.accountId, this.account, this.deletedAt});
|
||||||
factory _SnPostReaction.fromJson(Map<String, dynamic> json) => _$SnPostReactionFromJson(json);
|
factory _SnPostReaction.fromJson(Map<String, dynamic> json) => _$SnPostReactionFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@override final String symbol;
|
@override final String symbol;
|
||||||
@override final int attitude;
|
@override final int attitude;
|
||||||
@override final String postId;
|
@override final String postId;
|
||||||
@override final String accountId;
|
|
||||||
@override final DateTime createdAt;
|
@override final DateTime createdAt;
|
||||||
@override final DateTime updatedAt;
|
@override final DateTime updatedAt;
|
||||||
@override@JsonKey() final SnAccount? account;
|
@override final String? actorId;
|
||||||
|
@override final SnActivityPubActor? actor;
|
||||||
|
@override final String? accountId;
|
||||||
|
@override final SnAccount? account;
|
||||||
@override final DateTime? deletedAt;
|
@override final DateTime? deletedAt;
|
||||||
|
|
||||||
/// Create a copy of SnPostReaction
|
/// Create a copy of SnPostReaction
|
||||||
@@ -2171,16 +2235,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.actorId, actorId) || other.actorId == actorId)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,accountId,createdAt,updatedAt,account,deletedAt);
|
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,createdAt,updatedAt,actorId,actor,accountId,account,deletedAt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, account: $account, deletedAt: $deletedAt)';
|
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, createdAt: $createdAt, updatedAt: $updatedAt, actorId: $actorId, actor: $actor, accountId: $accountId, account: $account, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2191,11 +2255,11 @@ abstract mixin class _$SnPostReactionCopyWith<$Res> implements $SnPostReactionCo
|
|||||||
factory _$SnPostReactionCopyWith(_SnPostReaction value, $Res Function(_SnPostReaction) _then) = __$SnPostReactionCopyWithImpl;
|
factory _$SnPostReactionCopyWith(_SnPostReaction value, $Res Function(_SnPostReaction) _then) = __$SnPostReactionCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt
|
String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@override $SnAccountCopyWith<$Res>? get account;
|
@override $SnActivityPubActorCopyWith<$Res>? get actor;@override $SnAccountCopyWith<$Res>? get account;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -2208,16 +2272,18 @@ class __$SnPostReactionCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnPostReaction
|
/// Create a copy of SnPostReaction
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? account = freezed,Object? deletedAt = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? createdAt = null,Object? updatedAt = null,Object? actorId = freezed,Object? actor = freezed,Object? accountId = freezed,Object? account = freezed,Object? deletedAt = freezed,}) {
|
||||||
return _then(_SnPostReaction(
|
return _then(_SnPostReaction(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
|
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
|
||||||
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
|
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
|
||||||
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
|
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as String,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,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
as DateTime,actorId: freezed == actorId ? _self.actorId : actorId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnActivityPubActor?,accountId: freezed == 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?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
as SnAccount?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,
|
||||||
));
|
));
|
||||||
@@ -2227,6 +2293,18 @@ as DateTime?,
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||||
|
if (_self.actor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||||
|
return _then(_self.copyWith(actor: value));
|
||||||
|
});
|
||||||
|
}/// Create a copy of SnPostReaction
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
$SnAccountCopyWith<$Res>? get account {
|
$SnAccountCopyWith<$Res>? get account {
|
||||||
if (_self.account == null) {
|
if (_self.account == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -48,12 +48,22 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
|
|||||||
realm: json['realm'] == null
|
realm: json['realm'] == null
|
||||||
? null
|
? null
|
||||||
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
|
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
|
||||||
|
publisherId: json['publisher_id'] as String?,
|
||||||
|
publisher: json['publisher'] == null
|
||||||
|
? null
|
||||||
|
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
|
||||||
|
actorid: json['actorid'] as String?,
|
||||||
|
actor: json['actor'] == null
|
||||||
|
? null
|
||||||
|
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
|
||||||
|
fediverseUri: json['fediverse_uri'] as String?,
|
||||||
|
fediverseType: (json['fediverse_type'] as num?)?.toInt(),
|
||||||
|
contentType: (json['content_type'] as num?)?.toInt() ?? 0,
|
||||||
attachments:
|
attachments:
|
||||||
(json['attachments'] as List<dynamic>?)
|
(json['attachments'] as List<dynamic>?)
|
||||||
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
|
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
const [],
|
const [],
|
||||||
publisher: 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()),
|
||||||
@@ -123,8 +133,14 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
|
|||||||
'forwarded_post': instance.forwardedPost?.toJson(),
|
'forwarded_post': instance.forwardedPost?.toJson(),
|
||||||
'realm_id': instance.realmId,
|
'realm_id': instance.realmId,
|
||||||
'realm': instance.realm?.toJson(),
|
'realm': instance.realm?.toJson(),
|
||||||
|
'publisher_id': instance.publisherId,
|
||||||
|
'publisher': instance.publisher?.toJson(),
|
||||||
|
'actorid': instance.actorid,
|
||||||
|
'actor': instance.actor?.toJson(),
|
||||||
|
'fediverse_uri': instance.fediverseUri,
|
||||||
|
'fediverse_type': instance.fediverseType,
|
||||||
|
'content_type': instance.contentType,
|
||||||
'attachments': instance.attachments.map((e) => e.toJson()).toList(),
|
'attachments': instance.attachments.map((e) => e.toJson()).toList(),
|
||||||
'publisher': instance.publisher.toJson(),
|
|
||||||
'reactions_count': instance.reactionsCount,
|
'reactions_count': instance.reactionsCount,
|
||||||
'reactions_made': instance.reactionsMade,
|
'reactions_made': instance.reactionsMade,
|
||||||
'reactions': instance.reactions,
|
'reactions': instance.reactions,
|
||||||
@@ -232,9 +248,13 @@ _SnPostReaction _$SnPostReactionFromJson(Map<String, dynamic> json) =>
|
|||||||
symbol: json['symbol'] as String,
|
symbol: json['symbol'] as String,
|
||||||
attitude: (json['attitude'] as num).toInt(),
|
attitude: (json['attitude'] as num).toInt(),
|
||||||
postId: json['post_id'] as String,
|
postId: json['post_id'] as String,
|
||||||
accountId: json['account_id'] as String,
|
|
||||||
createdAt: DateTime.parse(json['created_at'] as String),
|
createdAt: DateTime.parse(json['created_at'] as String),
|
||||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||||
|
actorId: json['actor_id'] as String?,
|
||||||
|
actor: json['actor'] == null
|
||||||
|
? null
|
||||||
|
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
|
||||||
|
accountId: json['account_id'] as String?,
|
||||||
account: json['account'] == null
|
account: json['account'] == null
|
||||||
? null
|
? null
|
||||||
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||||
@@ -249,9 +269,11 @@ Map<String, dynamic> _$SnPostReactionToJson(_SnPostReaction instance) =>
|
|||||||
'symbol': instance.symbol,
|
'symbol': instance.symbol,
|
||||||
'attitude': instance.attitude,
|
'attitude': instance.attitude,
|
||||||
'post_id': instance.postId,
|
'post_id': instance.postId,
|
||||||
'account_id': instance.accountId,
|
|
||||||
'created_at': instance.createdAt.toIso8601String(),
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
|
'actor_id': instance.actorId,
|
||||||
|
'actor': instance.actor?.toJson(),
|
||||||
|
'account_id': instance.accountId,
|
||||||
'account': instance.account?.toJson(),
|
'account': instance.account?.toJson(),
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:island/models/file.dart';
|
|
||||||
|
|
||||||
part 'reference.freezed.dart';
|
|
||||||
part 'reference.g.dart';
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
sealed class Reference with _$Reference {
|
|
||||||
const factory Reference({
|
|
||||||
required String id,
|
|
||||||
@JsonKey(name: 'file_id') required String fileId,
|
|
||||||
SnCloudFile? file,
|
|
||||||
required String usage,
|
|
||||||
@JsonKey(name: 'resource_id') required String resourceId,
|
|
||||||
@JsonKey(name: 'expired_at') DateTime? expiredAt,
|
|
||||||
@JsonKey(name: 'created_at') required DateTime createdAt,
|
|
||||||
@JsonKey(name: 'updated_at') required DateTime updatedAt,
|
|
||||||
@JsonKey(name: 'deleted_at') DateTime? deletedAt,
|
|
||||||
}) = _Reference;
|
|
||||||
|
|
||||||
factory Reference.fromJson(Map<String, dynamic> json) =>
|
|
||||||
_$ReferenceFromJson(json);
|
|
||||||
}
|
|
||||||
@@ -1,319 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// coverage:ignore-file
|
|
||||||
// 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 'reference.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// dart format off
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$Reference {
|
|
||||||
|
|
||||||
String get id;@JsonKey(name: 'file_id') String get fileId; SnCloudFile? get file; String get usage;@JsonKey(name: 'resource_id') String get resourceId;@JsonKey(name: 'expired_at') DateTime? get expiredAt;@JsonKey(name: 'created_at') DateTime get createdAt;@JsonKey(name: 'updated_at') DateTime get updatedAt;@JsonKey(name: 'deleted_at') DateTime? get deletedAt;
|
|
||||||
/// Create a copy of Reference
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$ReferenceCopyWith<Reference> get copyWith => _$ReferenceCopyWithImpl<Reference>(this as Reference, _$identity);
|
|
||||||
|
|
||||||
/// Serializes this Reference to a JSON map.
|
|
||||||
Map<String, dynamic> toJson();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is Reference&&(identical(other.id, id) || other.id == id)&&(identical(other.fileId, fileId) || other.fileId == fileId)&&(identical(other.file, file) || other.file == file)&&(identical(other.usage, usage) || other.usage == usage)&&(identical(other.resourceId, resourceId) || other.resourceId == resourceId)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(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,id,fileId,file,usage,resourceId,expiredAt,createdAt,updatedAt,deletedAt);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'Reference(id: $id, fileId: $fileId, file: $file, usage: $usage, resourceId: $resourceId, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $ReferenceCopyWith<$Res> {
|
|
||||||
factory $ReferenceCopyWith(Reference value, $Res Function(Reference) _then) = _$ReferenceCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
String id,@JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage,@JsonKey(name: 'resource_id') String resourceId,@JsonKey(name: 'expired_at') DateTime? expiredAt,@JsonKey(name: 'created_at') DateTime createdAt,@JsonKey(name: 'updated_at') DateTime updatedAt,@JsonKey(name: 'deleted_at') DateTime? deletedAt
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$SnCloudFileCopyWith<$Res>? get file;
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$ReferenceCopyWithImpl<$Res>
|
|
||||||
implements $ReferenceCopyWith<$Res> {
|
|
||||||
_$ReferenceCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final Reference _self;
|
|
||||||
final $Res Function(Reference) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Reference
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? fileId = null,Object? file = freezed,Object? usage = null,Object? resourceId = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,fileId: null == fileId ? _self.fileId : fileId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,file: freezed == file ? _self.file : file // ignore: cast_nullable_to_non_nullable
|
|
||||||
as SnCloudFile?,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,resourceId: null == resourceId ? _self.resourceId : resourceId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // 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 Reference
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SnCloudFileCopyWith<$Res>? get file {
|
|
||||||
if (_self.file == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $SnCloudFileCopyWith<$Res>(_self.file!, (value) {
|
|
||||||
return _then(_self.copyWith(file: value));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Adds pattern-matching-related methods to [Reference].
|
|
||||||
extension ReferencePatterns on Reference {
|
|
||||||
/// A variant of `map` that fallback to returning `orElse`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _Reference value)? $default,{required TResult orElse(),}){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Reference() when $default != null:
|
|
||||||
return $default(_that);case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// Callbacks receives the raw object, upcasted.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case final Subclass2 value:
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _Reference value) $default,){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Reference():
|
|
||||||
return $default(_that);}
|
|
||||||
}
|
|
||||||
/// A variant of `map` that fallback to returning `null`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _Reference value)? $default,){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Reference() when $default != null:
|
|
||||||
return $default(_that);case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to an `orElse` callback.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, @JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage, @JsonKey(name: 'resource_id') String resourceId, @JsonKey(name: 'expired_at') DateTime? expiredAt, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime updatedAt, @JsonKey(name: 'deleted_at') DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Reference() when $default != null:
|
|
||||||
return $default(_that.id,_that.fileId,_that.file,_that.usage,_that.resourceId,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// As opposed to `map`, this offers destructuring.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case Subclass2(:final field2):
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, @JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage, @JsonKey(name: 'resource_id') String resourceId, @JsonKey(name: 'expired_at') DateTime? expiredAt, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime updatedAt, @JsonKey(name: 'deleted_at') DateTime? deletedAt) $default,) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Reference():
|
|
||||||
return $default(_that.id,_that.fileId,_that.file,_that.usage,_that.resourceId,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to returning `null`
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, @JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage, @JsonKey(name: 'resource_id') String resourceId, @JsonKey(name: 'expired_at') DateTime? expiredAt, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime updatedAt, @JsonKey(name: 'deleted_at') DateTime? deletedAt)? $default,) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _Reference() when $default != null:
|
|
||||||
return $default(_that.id,_that.fileId,_that.file,_that.usage,_that.resourceId,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@JsonSerializable()
|
|
||||||
|
|
||||||
class _Reference implements Reference {
|
|
||||||
const _Reference({required this.id, @JsonKey(name: 'file_id') required this.fileId, this.file, required this.usage, @JsonKey(name: 'resource_id') required this.resourceId, @JsonKey(name: 'expired_at') this.expiredAt, @JsonKey(name: 'created_at') required this.createdAt, @JsonKey(name: 'updated_at') required this.updatedAt, @JsonKey(name: 'deleted_at') this.deletedAt});
|
|
||||||
factory _Reference.fromJson(Map<String, dynamic> json) => _$ReferenceFromJson(json);
|
|
||||||
|
|
||||||
@override final String id;
|
|
||||||
@override@JsonKey(name: 'file_id') final String fileId;
|
|
||||||
@override final SnCloudFile? file;
|
|
||||||
@override final String usage;
|
|
||||||
@override@JsonKey(name: 'resource_id') final String resourceId;
|
|
||||||
@override@JsonKey(name: 'expired_at') final DateTime? expiredAt;
|
|
||||||
@override@JsonKey(name: 'created_at') final DateTime createdAt;
|
|
||||||
@override@JsonKey(name: 'updated_at') final DateTime updatedAt;
|
|
||||||
@override@JsonKey(name: 'deleted_at') final DateTime? deletedAt;
|
|
||||||
|
|
||||||
/// Create a copy of Reference
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$ReferenceCopyWith<_Reference> get copyWith => __$ReferenceCopyWithImpl<_Reference>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$ReferenceToJson(this, );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Reference&&(identical(other.id, id) || other.id == id)&&(identical(other.fileId, fileId) || other.fileId == fileId)&&(identical(other.file, file) || other.file == file)&&(identical(other.usage, usage) || other.usage == usage)&&(identical(other.resourceId, resourceId) || other.resourceId == resourceId)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(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,id,fileId,file,usage,resourceId,expiredAt,createdAt,updatedAt,deletedAt);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'Reference(id: $id, fileId: $fileId, file: $file, usage: $usage, resourceId: $resourceId, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$ReferenceCopyWith<$Res> implements $ReferenceCopyWith<$Res> {
|
|
||||||
factory _$ReferenceCopyWith(_Reference value, $Res Function(_Reference) _then) = __$ReferenceCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
String id,@JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage,@JsonKey(name: 'resource_id') String resourceId,@JsonKey(name: 'expired_at') DateTime? expiredAt,@JsonKey(name: 'created_at') DateTime createdAt,@JsonKey(name: 'updated_at') DateTime updatedAt,@JsonKey(name: 'deleted_at') DateTime? deletedAt
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
@override $SnCloudFileCopyWith<$Res>? get file;
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$ReferenceCopyWithImpl<$Res>
|
|
||||||
implements _$ReferenceCopyWith<$Res> {
|
|
||||||
__$ReferenceCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _Reference _self;
|
|
||||||
final $Res Function(_Reference) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Reference
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? fileId = null,Object? file = freezed,Object? usage = null,Object? resourceId = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
|
||||||
return _then(_Reference(
|
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,fileId: null == fileId ? _self.fileId : fileId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,file: freezed == file ? _self.file : file // ignore: cast_nullable_to_non_nullable
|
|
||||||
as SnCloudFile?,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,resourceId: null == resourceId ? _self.resourceId : resourceId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // 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 Reference
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SnCloudFileCopyWith<$Res>? get file {
|
|
||||||
if (_self.file == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $SnCloudFileCopyWith<$Res>(_self.file!, (value) {
|
|
||||||
return _then(_self.copyWith(file: value));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dart format on
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'reference.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
_Reference _$ReferenceFromJson(Map<String, dynamic> json) => _Reference(
|
|
||||||
id: json['id'] as String,
|
|
||||||
fileId: json['file_id'] as String,
|
|
||||||
file: json['file'] == null
|
|
||||||
? null
|
|
||||||
: SnCloudFile.fromJson(json['file'] as Map<String, dynamic>),
|
|
||||||
usage: json['usage'] as String,
|
|
||||||
resourceId: json['resource_id'] as String,
|
|
||||||
expiredAt: json['expired_at'] == null
|
|
||||||
? null
|
|
||||||
: DateTime.parse(json['expired_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> _$ReferenceToJson(_Reference instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'id': instance.id,
|
|
||||||
'file_id': instance.fileId,
|
|
||||||
'file': instance.file?.toJson(),
|
|
||||||
'usage': instance.usage,
|
|
||||||
'resource_id': instance.resourceId,
|
|
||||||
'expired_at': instance.expiredAt?.toIso8601String(),
|
|
||||||
'created_at': instance.createdAt.toIso8601String(),
|
|
||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
|
||||||
};
|
|
||||||
@@ -12,9 +12,10 @@ sealed class SnRelationship with _$SnRelationship {
|
|||||||
required DateTime? updatedAt,
|
required DateTime? updatedAt,
|
||||||
required DateTime? deletedAt,
|
required DateTime? deletedAt,
|
||||||
required String accountId,
|
required String accountId,
|
||||||
required SnAccount account,
|
// Usually the account was not included in the response
|
||||||
|
required SnAccount? account,
|
||||||
required String relatedId,
|
required String relatedId,
|
||||||
required SnAccount related,
|
required SnAccount? related,
|
||||||
required DateTime? expiredAt,
|
required DateTime? expiredAt,
|
||||||
required int status,
|
required int status,
|
||||||
}) = _SnRelationship;
|
}) = _SnRelationship;
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnRelationship {
|
mixin _$SnRelationship {
|
||||||
|
|
||||||
DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; String get accountId; SnAccount get account; String get relatedId; SnAccount get related; DateTime? get expiredAt; int get status;
|
DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; String get accountId;// Usually the account was not included in the response
|
||||||
|
SnAccount? get account; String get relatedId; SnAccount? get related; DateTime? get expiredAt; int get status;
|
||||||
/// Create a copy of SnRelationship
|
/// Create a copy of SnRelationship
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -48,11 +49,11 @@ abstract mixin class $SnRelationshipCopyWith<$Res> {
|
|||||||
factory $SnRelationshipCopyWith(SnRelationship value, $Res Function(SnRelationship) _then) = _$SnRelationshipCopyWithImpl;
|
factory $SnRelationshipCopyWith(SnRelationship value, $Res Function(SnRelationship) _then) = _$SnRelationshipCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount account, String relatedId, SnAccount related, DateTime? expiredAt, int status
|
DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount? account, String relatedId, SnAccount? related, DateTime? expiredAt, int status
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$SnAccountCopyWith<$Res> get account;$SnAccountCopyWith<$Res> get related;
|
$SnAccountCopyWith<$Res>? get account;$SnAccountCopyWith<$Res>? get related;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -65,16 +66,16 @@ class _$SnRelationshipCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnRelationship
|
/// Create a copy of SnRelationship
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? accountId = null,Object? account = null,Object? relatedId = null,Object? related = null,Object? expiredAt = freezed,Object? status = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? accountId = null,Object? account = freezed,Object? relatedId = null,Object? related = freezed,Object? expiredAt = freezed,Object? status = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
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?,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?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
as DateTime?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,account: null == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||||
as SnAccount,relatedId: null == relatedId ? _self.relatedId : relatedId // ignore: cast_nullable_to_non_nullable
|
as SnAccount?,relatedId: null == relatedId ? _self.relatedId : relatedId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,related: null == related ? _self.related : related // ignore: cast_nullable_to_non_nullable
|
as String,related: freezed == related ? _self.related : related // ignore: cast_nullable_to_non_nullable
|
||||||
as SnAccount,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
as SnAccount?,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
as DateTime?,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
));
|
));
|
||||||
@@ -83,18 +84,24 @@ as int,
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SnAccountCopyWith<$Res> get account {
|
$SnAccountCopyWith<$Res>? get account {
|
||||||
|
if (_self.account == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $SnAccountCopyWith<$Res>(_self.account, (value) {
|
return $SnAccountCopyWith<$Res>(_self.account!, (value) {
|
||||||
return _then(_self.copyWith(account: value));
|
return _then(_self.copyWith(account: value));
|
||||||
});
|
});
|
||||||
}/// Create a copy of SnRelationship
|
}/// Create a copy of SnRelationship
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SnAccountCopyWith<$Res> get related {
|
$SnAccountCopyWith<$Res>? get related {
|
||||||
|
if (_self.related == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $SnAccountCopyWith<$Res>(_self.related, (value) {
|
return $SnAccountCopyWith<$Res>(_self.related!, (value) {
|
||||||
return _then(_self.copyWith(related: value));
|
return _then(_self.copyWith(related: value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -176,7 +183,7 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount account, String relatedId, SnAccount related, DateTime? expiredAt, int status)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount? account, String relatedId, SnAccount? related, DateTime? expiredAt, int status)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnRelationship() when $default != null:
|
case _SnRelationship() when $default != null:
|
||||||
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,_that.account,_that.relatedId,_that.related,_that.expiredAt,_that.status);case _:
|
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,_that.account,_that.relatedId,_that.related,_that.expiredAt,_that.status);case _:
|
||||||
@@ -197,7 +204,7 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount account, String relatedId, SnAccount related, DateTime? expiredAt, int status) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount? account, String relatedId, SnAccount? related, DateTime? expiredAt, int status) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnRelationship():
|
case _SnRelationship():
|
||||||
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,_that.account,_that.relatedId,_that.related,_that.expiredAt,_that.status);}
|
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,_that.account,_that.relatedId,_that.related,_that.expiredAt,_that.status);}
|
||||||
@@ -214,7 +221,7 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount account, String relatedId, SnAccount related, DateTime? expiredAt, int status)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount? account, String relatedId, SnAccount? related, DateTime? expiredAt, int status)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnRelationship() when $default != null:
|
case _SnRelationship() when $default != null:
|
||||||
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,_that.account,_that.relatedId,_that.related,_that.expiredAt,_that.status);case _:
|
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.accountId,_that.account,_that.relatedId,_that.related,_that.expiredAt,_that.status);case _:
|
||||||
@@ -236,9 +243,10 @@ class _SnRelationship implements SnRelationship {
|
|||||||
@override final DateTime? updatedAt;
|
@override final DateTime? updatedAt;
|
||||||
@override final DateTime? deletedAt;
|
@override final DateTime? deletedAt;
|
||||||
@override final String accountId;
|
@override final String accountId;
|
||||||
@override final SnAccount account;
|
// Usually the account was not included in the response
|
||||||
|
@override final SnAccount? account;
|
||||||
@override final String relatedId;
|
@override final String relatedId;
|
||||||
@override final SnAccount related;
|
@override final SnAccount? related;
|
||||||
@override final DateTime? expiredAt;
|
@override final DateTime? expiredAt;
|
||||||
@override final int status;
|
@override final int status;
|
||||||
|
|
||||||
@@ -275,11 +283,11 @@ abstract mixin class _$SnRelationshipCopyWith<$Res> implements $SnRelationshipCo
|
|||||||
factory _$SnRelationshipCopyWith(_SnRelationship value, $Res Function(_SnRelationship) _then) = __$SnRelationshipCopyWithImpl;
|
factory _$SnRelationshipCopyWith(_SnRelationship value, $Res Function(_SnRelationship) _then) = __$SnRelationshipCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount account, String relatedId, SnAccount related, DateTime? expiredAt, int status
|
DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String accountId, SnAccount? account, String relatedId, SnAccount? related, DateTime? expiredAt, int status
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@override $SnAccountCopyWith<$Res> get account;@override $SnAccountCopyWith<$Res> get related;
|
@override $SnAccountCopyWith<$Res>? get account;@override $SnAccountCopyWith<$Res>? get related;
|
||||||
|
|
||||||
}
|
}
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -292,16 +300,16 @@ class __$SnRelationshipCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnRelationship
|
/// Create a copy of SnRelationship
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? accountId = null,Object? account = null,Object? relatedId = null,Object? related = null,Object? expiredAt = freezed,Object? status = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? accountId = null,Object? account = freezed,Object? relatedId = null,Object? related = freezed,Object? expiredAt = freezed,Object? status = null,}) {
|
||||||
return _then(_SnRelationship(
|
return _then(_SnRelationship(
|
||||||
createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
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?,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?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
as DateTime?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,account: null == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||||
as SnAccount,relatedId: null == relatedId ? _self.relatedId : relatedId // ignore: cast_nullable_to_non_nullable
|
as SnAccount?,relatedId: null == relatedId ? _self.relatedId : relatedId // ignore: cast_nullable_to_non_nullable
|
||||||
as String,related: null == related ? _self.related : related // ignore: cast_nullable_to_non_nullable
|
as String,related: freezed == related ? _self.related : related // ignore: cast_nullable_to_non_nullable
|
||||||
as SnAccount,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
as SnAccount?,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
as DateTime?,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
));
|
));
|
||||||
@@ -311,18 +319,24 @@ as int,
|
|||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SnAccountCopyWith<$Res> get account {
|
$SnAccountCopyWith<$Res>? get account {
|
||||||
|
if (_self.account == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $SnAccountCopyWith<$Res>(_self.account, (value) {
|
return $SnAccountCopyWith<$Res>(_self.account!, (value) {
|
||||||
return _then(_self.copyWith(account: value));
|
return _then(_self.copyWith(account: value));
|
||||||
});
|
});
|
||||||
}/// Create a copy of SnRelationship
|
}/// Create a copy of SnRelationship
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SnAccountCopyWith<$Res> get related {
|
$SnAccountCopyWith<$Res>? get related {
|
||||||
|
if (_self.related == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return $SnAccountCopyWith<$Res>(_self.related, (value) {
|
return $SnAccountCopyWith<$Res>(_self.related!, (value) {
|
||||||
return _then(_self.copyWith(related: value));
|
return _then(_self.copyWith(related: value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,13 @@ _SnRelationship _$SnRelationshipFromJson(Map<String, dynamic> json) =>
|
|||||||
? null
|
? null
|
||||||
: DateTime.parse(json['deleted_at'] as String),
|
: DateTime.parse(json['deleted_at'] as String),
|
||||||
accountId: json['account_id'] as String,
|
accountId: json['account_id'] as String,
|
||||||
account: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
account: json['account'] == null
|
||||||
|
? null
|
||||||
|
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||||
relatedId: json['related_id'] as String,
|
relatedId: json['related_id'] as String,
|
||||||
related: SnAccount.fromJson(json['related'] as Map<String, dynamic>),
|
related: json['related'] == null
|
||||||
|
? null
|
||||||
|
: SnAccount.fromJson(json['related'] as Map<String, dynamic>),
|
||||||
expiredAt: json['expired_at'] == null
|
expiredAt: json['expired_at'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json['expired_at'] as String),
|
: DateTime.parse(json['expired_at'] as String),
|
||||||
@@ -33,9 +37,9 @@ Map<String, dynamic> _$SnRelationshipToJson(_SnRelationship instance) =>
|
|||||||
'updated_at': instance.updatedAt?.toIso8601String(),
|
'updated_at': instance.updatedAt?.toIso8601String(),
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
'account_id': instance.accountId,
|
'account_id': instance.accountId,
|
||||||
'account': instance.account.toJson(),
|
'account': instance.account?.toJson(),
|
||||||
'related_id': instance.relatedId,
|
'related_id': instance.relatedId,
|
||||||
'related': instance.related.toJson(),
|
'related': instance.related?.toJson(),
|
||||||
'expired_at': instance.expiredAt?.toIso8601String(),
|
'expired_at': instance.expiredAt?.toIso8601String(),
|
||||||
'status': instance.status,
|
'status': instance.status,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ final List<RouteItem> kAvailableRoutes = [
|
|||||||
icon: Symbols.explore,
|
icon: Symbols.explore,
|
||||||
),
|
),
|
||||||
RouteItem(
|
RouteItem(
|
||||||
name: 'searchPosts'.tr(),
|
name: 'universalSearch'.tr(),
|
||||||
path: '/posts/search',
|
path: '/search',
|
||||||
description: 'searchPostsDescription'.tr(),
|
description: 'universalSearchDescription'.tr(),
|
||||||
searchableAliases: ['search', 'posts'],
|
searchableAliases: ['search', 'universal', 'fediverse'],
|
||||||
icon: Symbols.search,
|
icon: Symbols.search,
|
||||||
),
|
),
|
||||||
RouteItem(
|
RouteItem(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ part of 'activity_rpc.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(presenceActivities)
|
@ProviderFor(presenceActivities)
|
||||||
const presenceActivitiesProvider = PresenceActivitiesFamily._();
|
final presenceActivitiesProvider = PresenceActivitiesFamily._();
|
||||||
|
|
||||||
final class PresenceActivitiesProvider
|
final class PresenceActivitiesProvider
|
||||||
extends
|
extends
|
||||||
@@ -22,7 +22,7 @@ final class PresenceActivitiesProvider
|
|||||||
with
|
with
|
||||||
$FutureModifier<List<SnPresenceActivity>>,
|
$FutureModifier<List<SnPresenceActivity>>,
|
||||||
$FutureProvider<List<SnPresenceActivity>> {
|
$FutureProvider<List<SnPresenceActivity>> {
|
||||||
const PresenceActivitiesProvider._({
|
PresenceActivitiesProvider._({
|
||||||
required PresenceActivitiesFamily super.from,
|
required PresenceActivitiesFamily super.from,
|
||||||
required String super.argument,
|
required String super.argument,
|
||||||
}) : super(
|
}) : super(
|
||||||
@@ -71,7 +71,7 @@ String _$presenceActivitiesHash() =>
|
|||||||
|
|
||||||
final class PresenceActivitiesFamily extends $Family
|
final class PresenceActivitiesFamily extends $Family
|
||||||
with $FunctionalFamilyOverride<FutureOr<List<SnPresenceActivity>>, String> {
|
with $FunctionalFamilyOverride<FutureOr<List<SnPresenceActivity>>, String> {
|
||||||
const PresenceActivitiesFamily._()
|
PresenceActivitiesFamily._()
|
||||||
: super(
|
: super(
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'presenceActivitiesProvider',
|
name: r'presenceActivitiesProvider',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ final articleDetailProvider = FutureProvider.autoDispose
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await dio.get<Map<String, dynamic>>(
|
final response = await dio.get<Map<String, dynamic>>(
|
||||||
'/sphere/feeds/articles/$articleId',
|
'/insight/feeds/articles/$articleId',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200 && response.data != null) {
|
if (response.statusCode == 200 && response.data != null) {
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import 'package:island/talker.dart';
|
|||||||
part 'call.g.dart';
|
part 'call.g.dart';
|
||||||
part 'call.freezed.dart';
|
part 'call.freezed.dart';
|
||||||
|
|
||||||
|
enum ViewMode { grid, stage }
|
||||||
|
|
||||||
String formatDuration(Duration duration) {
|
String formatDuration(Duration duration) {
|
||||||
String negativeSign = duration.isNegative ? '-' : '';
|
String negativeSign = duration.isNegative ? '-' : '';
|
||||||
String twoDigits(int n) => n.toString().padLeft(2, "0");
|
String twoDigits(int n) => n.toString().padLeft(2, "0");
|
||||||
@@ -33,6 +35,7 @@ sealed class CallState with _$CallState {
|
|||||||
required bool isScreenSharing,
|
required bool isScreenSharing,
|
||||||
required bool isSpeakerphone,
|
required bool isSpeakerphone,
|
||||||
@Default(Duration(seconds: 0)) Duration duration,
|
@Default(Duration(seconds: 0)) Duration duration,
|
||||||
|
@Default(ViewMode.grid) ViewMode viewMode,
|
||||||
String? error,
|
String? error,
|
||||||
}) = _CallState;
|
}) = _CallState;
|
||||||
}
|
}
|
||||||
@@ -84,6 +87,7 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
isCameraEnabled: false,
|
isCameraEnabled: false,
|
||||||
isScreenSharing: false,
|
isScreenSharing: false,
|
||||||
isSpeakerphone: true,
|
isSpeakerphone: true,
|
||||||
|
viewMode: ViewMode.grid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +245,7 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
final ongoingCall = await ref.read(ongoingCallProvider(roomId).future);
|
final ongoingCall = await ref.read(ongoingCallProvider(roomId).future);
|
||||||
final response = await apiClient.get(
|
final response = await apiClient.get(
|
||||||
'/sphere/chat/realtime/$roomId/join',
|
'/messager/chat/realtime/$roomId/join',
|
||||||
);
|
);
|
||||||
if (response.statusCode == 200 && response.data != null) {
|
if (response.statusCode == 200 && response.data != null) {
|
||||||
final data = response.data;
|
final data = response.data;
|
||||||
@@ -418,6 +422,14 @@ class CallNotifier extends _$CallNotifier {
|
|||||||
return participantsVolumes[live.remoteParticipant.sid] ?? 1;
|
return participantsVolumes[live.remoteParticipant.sid] ?? 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toggleViewMode() {
|
||||||
|
state = state.copyWith(
|
||||||
|
viewMode: state.viewMode == ViewMode.grid
|
||||||
|
? ViewMode.stage
|
||||||
|
: ViewMode.grid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
error: null,
|
error: null,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$CallState implements DiagnosticableTreeMixin {
|
mixin _$CallState implements DiagnosticableTreeMixin {
|
||||||
|
|
||||||
bool get isConnected; bool get isMicrophoneEnabled; bool get isCameraEnabled; bool get isScreenSharing; bool get isSpeakerphone; Duration get duration; String? get error;
|
bool get isConnected; bool get isMicrophoneEnabled; bool get isCameraEnabled; bool get isScreenSharing; bool get isSpeakerphone; Duration get duration; ViewMode get viewMode; String? get error;
|
||||||
/// Create a copy of CallState
|
/// Create a copy of CallState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -26,21 +26,21 @@ $CallStateCopyWith<CallState> get copyWith => _$CallStateCopyWithImpl<CallState>
|
|||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
properties
|
properties
|
||||||
..add(DiagnosticsProperty('type', 'CallState'))
|
..add(DiagnosticsProperty('type', 'CallState'))
|
||||||
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('error', error));
|
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('viewMode', viewMode))..add(DiagnosticsProperty('error', error));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.viewMode, viewMode) || other.viewMode == viewMode)&&(identical(other.error, error) || other.error == error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,error);
|
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,viewMode,error);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, error: $error)';
|
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, viewMode: $viewMode, error: $error)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ abstract mixin class $CallStateCopyWith<$Res> {
|
|||||||
factory $CallStateCopyWith(CallState value, $Res Function(CallState) _then) = _$CallStateCopyWithImpl;
|
factory $CallStateCopyWith(CallState value, $Res Function(CallState) _then) = _$CallStateCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error
|
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ class _$CallStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of CallState
|
/// Create a copy of CallState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? error = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? viewMode = null,Object? error = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -76,7 +76,8 @@ as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCam
|
|||||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||||
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
as Duration,viewMode: null == viewMode ? _self.viewMode : viewMode // ignore: cast_nullable_to_non_nullable
|
||||||
|
as ViewMode,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -159,10 +160,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _CallState() when $default != null:
|
case _CallState() when $default != null:
|
||||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);case _:
|
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.viewMode,_that.error);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -180,10 +181,10 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _CallState():
|
case _CallState():
|
||||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);}
|
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.viewMode,_that.error);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -197,10 +198,10 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _CallState() when $default != null:
|
case _CallState() when $default != null:
|
||||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);case _:
|
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.viewMode,_that.error);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -212,7 +213,7 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
|||||||
|
|
||||||
|
|
||||||
class _CallState with DiagnosticableTreeMixin implements CallState {
|
class _CallState with DiagnosticableTreeMixin implements CallState {
|
||||||
const _CallState({required this.isConnected, required this.isMicrophoneEnabled, required this.isCameraEnabled, required this.isScreenSharing, required this.isSpeakerphone, this.duration = const Duration(seconds: 0), this.error});
|
const _CallState({required this.isConnected, required this.isMicrophoneEnabled, required this.isCameraEnabled, required this.isScreenSharing, required this.isSpeakerphone, this.duration = const Duration(seconds: 0), this.viewMode = ViewMode.grid, this.error});
|
||||||
|
|
||||||
|
|
||||||
@override final bool isConnected;
|
@override final bool isConnected;
|
||||||
@@ -221,6 +222,7 @@ class _CallState with DiagnosticableTreeMixin implements CallState {
|
|||||||
@override final bool isScreenSharing;
|
@override final bool isScreenSharing;
|
||||||
@override final bool isSpeakerphone;
|
@override final bool isSpeakerphone;
|
||||||
@override@JsonKey() final Duration duration;
|
@override@JsonKey() final Duration duration;
|
||||||
|
@override@JsonKey() final ViewMode viewMode;
|
||||||
@override final String? error;
|
@override final String? error;
|
||||||
|
|
||||||
/// Create a copy of CallState
|
/// Create a copy of CallState
|
||||||
@@ -234,21 +236,21 @@ _$CallStateCopyWith<_CallState> get copyWith => __$CallStateCopyWithImpl<_CallSt
|
|||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
properties
|
properties
|
||||||
..add(DiagnosticsProperty('type', 'CallState'))
|
..add(DiagnosticsProperty('type', 'CallState'))
|
||||||
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('error', error));
|
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('viewMode', viewMode))..add(DiagnosticsProperty('error', error));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.viewMode, viewMode) || other.viewMode == viewMode)&&(identical(other.error, error) || other.error == error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,error);
|
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,viewMode,error);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, error: $error)';
|
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, viewMode: $viewMode, error: $error)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -259,7 +261,7 @@ abstract mixin class _$CallStateCopyWith<$Res> implements $CallStateCopyWith<$Re
|
|||||||
factory _$CallStateCopyWith(_CallState value, $Res Function(_CallState) _then) = __$CallStateCopyWithImpl;
|
factory _$CallStateCopyWith(_CallState value, $Res Function(_CallState) _then) = __$CallStateCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error
|
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -276,7 +278,7 @@ class __$CallStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of CallState
|
/// Create a copy of CallState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? error = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? viewMode = null,Object? error = freezed,}) {
|
||||||
return _then(_CallState(
|
return _then(_CallState(
|
||||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -284,7 +286,8 @@ as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCam
|
|||||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||||
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
as Duration,viewMode: null == viewMode ? _self.viewMode : viewMode // ignore: cast_nullable_to_non_nullable
|
||||||
|
as ViewMode,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ part of 'call.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(CallNotifier)
|
@ProviderFor(CallNotifier)
|
||||||
const callProvider = CallNotifierProvider._();
|
final callProvider = CallNotifierProvider._();
|
||||||
|
|
||||||
final class CallNotifierProvider
|
final class CallNotifierProvider
|
||||||
extends $NotifierProvider<CallNotifier, CallState> {
|
extends $NotifierProvider<CallNotifier, CallState> {
|
||||||
const CallNotifierProvider._()
|
CallNotifierProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
@@ -41,14 +41,13 @@ final class CallNotifierProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$callNotifierHash() => r'ef4e3e9c9d411cf9dce1ceb456a3b866b2c87db3';
|
String _$callNotifierHash() => r'caa03913d98c6d98448af44059db5ef72b5d58f6';
|
||||||
|
|
||||||
abstract class _$CallNotifier extends $Notifier<CallState> {
|
abstract class _$CallNotifier extends $Notifier<CallState> {
|
||||||
CallState build();
|
CallState build();
|
||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build();
|
|
||||||
final ref = this.ref as $Ref<CallState, CallState>;
|
final ref = this.ref as $Ref<CallState, CallState>;
|
||||||
final element =
|
final element =
|
||||||
ref.element
|
ref.element
|
||||||
@@ -58,6 +57,6 @@ abstract class _$CallNotifier extends $Notifier<CallState> {
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, build);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class ChatOnlineCountNotifier extends _$ChatOnlineCountNotifier {
|
|||||||
|
|
||||||
// Fetch initial online count
|
// Fetch initial online count
|
||||||
final response = await apiClient.get(
|
final response = await apiClient.get(
|
||||||
'/sphere/chat/$chatroomId/members/online',
|
'/messager/chat/$chatroomId/members/online',
|
||||||
);
|
);
|
||||||
final initialCount = response.data as int;
|
final initialCount = response.data as int;
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ part of 'chat_online_count.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(ChatOnlineCountNotifier)
|
@ProviderFor(ChatOnlineCountNotifier)
|
||||||
const chatOnlineCountProvider = ChatOnlineCountNotifierFamily._();
|
final chatOnlineCountProvider = ChatOnlineCountNotifierFamily._();
|
||||||
|
|
||||||
final class ChatOnlineCountNotifierProvider
|
final class ChatOnlineCountNotifierProvider
|
||||||
extends $AsyncNotifierProvider<ChatOnlineCountNotifier, int> {
|
extends $AsyncNotifierProvider<ChatOnlineCountNotifier, int> {
|
||||||
const ChatOnlineCountNotifierProvider._({
|
ChatOnlineCountNotifierProvider._({
|
||||||
required ChatOnlineCountNotifierFamily super.from,
|
required ChatOnlineCountNotifierFamily super.from,
|
||||||
required String super.argument,
|
required String super.argument,
|
||||||
}) : super(
|
}) : super(
|
||||||
@@ -52,7 +52,7 @@ final class ChatOnlineCountNotifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$chatOnlineCountNotifierHash() =>
|
String _$chatOnlineCountNotifierHash() =>
|
||||||
r'19af8fd0e9f62c65e12a68215406776085235fa3';
|
r'b2f9f17bfece1937ec90590b8f11db2bec923156';
|
||||||
|
|
||||||
final class ChatOnlineCountNotifierFamily extends $Family
|
final class ChatOnlineCountNotifierFamily extends $Family
|
||||||
with
|
with
|
||||||
@@ -63,7 +63,7 @@ final class ChatOnlineCountNotifierFamily extends $Family
|
|||||||
FutureOr<int>,
|
FutureOr<int>,
|
||||||
String
|
String
|
||||||
> {
|
> {
|
||||||
const ChatOnlineCountNotifierFamily._()
|
ChatOnlineCountNotifierFamily._()
|
||||||
: super(
|
: super(
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'chatOnlineCountProvider',
|
name: r'chatOnlineCountProvider',
|
||||||
@@ -87,7 +87,6 @@ abstract class _$ChatOnlineCountNotifier extends $AsyncNotifier<int> {
|
|||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build(_$args);
|
|
||||||
final ref = this.ref as $Ref<AsyncValue<int>, int>;
|
final ref = this.ref as $Ref<AsyncValue<int>, int>;
|
||||||
final element =
|
final element =
|
||||||
ref.element
|
ref.element
|
||||||
@@ -97,6 +96,6 @@ abstract class _$ChatOnlineCountNotifier extends $AsyncNotifier<int> {
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, () => build(_$args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
|
|||||||
Future(() async {
|
Future(() async {
|
||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat');
|
final resp = await client.get('/messager/chat');
|
||||||
final remoteRooms = resp.data
|
final remoteRooms = resp.data
|
||||||
.map((e) => SnChatRoom.fromJson(e))
|
.map((e) => SnChatRoom.fromJson(e))
|
||||||
.cast<SnChatRoom>()
|
.cast<SnChatRoom>()
|
||||||
@@ -122,7 +122,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
|
|||||||
|
|
||||||
// Fallback to API
|
// Fallback to API
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat');
|
final resp = await client.get('/messager/chat');
|
||||||
final rooms = resp.data
|
final rooms = resp.data
|
||||||
.map((e) => SnChatRoom.fromJson(e))
|
.map((e) => SnChatRoom.fromJson(e))
|
||||||
.cast<SnChatRoom>()
|
.cast<SnChatRoom>()
|
||||||
@@ -306,7 +306,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
|
|||||||
Future(() async {
|
Future(() async {
|
||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat/$identifier');
|
final resp = await client.get('/messager/chat/$identifier');
|
||||||
final remoteRoom = SnChatRoom.fromJson(resp.data);
|
final remoteRoom = SnChatRoom.fromJson(resp.data);
|
||||||
// Update state with fresh data directly without saving to DB
|
// Update state with fresh data directly without saving to DB
|
||||||
// DB will be updated by ChatRoomJoinedNotifier's full sync
|
// DB will be updated by ChatRoomJoinedNotifier's full sync
|
||||||
@@ -321,7 +321,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
|
|||||||
// Fallback to API
|
// Fallback to API
|
||||||
try {
|
try {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat/$identifier');
|
final resp = await client.get('/messager/chat/$identifier');
|
||||||
final room = SnChatRoom.fromJson(resp.data);
|
final room = SnChatRoom.fromJson(resp.data);
|
||||||
await db.saveChatRooms([room]);
|
await db.saveChatRooms([room]);
|
||||||
return room;
|
return room;
|
||||||
@@ -375,7 +375,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
|||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final resp = await client.get(
|
final resp = await client.get(
|
||||||
'/sphere/chat/$identifier/members/me',
|
'/messager/chat/$identifier/members/me',
|
||||||
);
|
);
|
||||||
final remoteMember = SnChatMember.fromJson(resp.data);
|
final remoteMember = SnChatMember.fromJson(resp.data);
|
||||||
await db.saveMember(remoteMember);
|
await db.saveMember(remoteMember);
|
||||||
@@ -396,7 +396,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
|||||||
// Fallback to API
|
// Fallback to API
|
||||||
try {
|
try {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat/$identifier/members/me');
|
final resp = await client.get('/messager/chat/$identifier/members/me');
|
||||||
final member = SnChatMember.fromJson(resp.data);
|
final member = SnChatMember.fromJson(resp.data);
|
||||||
await db.saveMember(member);
|
await db.saveMember(member);
|
||||||
return member;
|
return member;
|
||||||
@@ -444,7 +444,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
|||||||
@riverpod
|
@riverpod
|
||||||
Future<List<SnChatMember>> chatroomInvites(Ref ref) async {
|
Future<List<SnChatMember>> chatroomInvites(Ref ref) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat/invites');
|
final resp = await client.get('/messager/chat/invites');
|
||||||
return resp.data
|
return resp.data
|
||||||
.map((e) => SnChatMember.fromJson(e))
|
.map((e) => SnChatMember.fromJson(e))
|
||||||
.cast<SnChatMember>()
|
.cast<SnChatMember>()
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ part of 'chat_room.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(ChatRoomJoinedNotifier)
|
@ProviderFor(ChatRoomJoinedNotifier)
|
||||||
const chatRoomJoinedProvider = ChatRoomJoinedNotifierProvider._();
|
final chatRoomJoinedProvider = ChatRoomJoinedNotifierProvider._();
|
||||||
|
|
||||||
final class ChatRoomJoinedNotifierProvider
|
final class ChatRoomJoinedNotifierProvider
|
||||||
extends $AsyncNotifierProvider<ChatRoomJoinedNotifier, List<SnChatRoom>> {
|
extends $AsyncNotifierProvider<ChatRoomJoinedNotifier, List<SnChatRoom>> {
|
||||||
const ChatRoomJoinedNotifierProvider._()
|
ChatRoomJoinedNotifierProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
@@ -34,7 +34,7 @@ final class ChatRoomJoinedNotifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$chatRoomJoinedNotifierHash() =>
|
String _$chatRoomJoinedNotifierHash() =>
|
||||||
r'e69955be56ef2c04a8062a8a65925e0a23bfcbaa';
|
r'b3726e10298b99a8529c5e28a5c402b95016f096';
|
||||||
|
|
||||||
abstract class _$ChatRoomJoinedNotifier
|
abstract class _$ChatRoomJoinedNotifier
|
||||||
extends $AsyncNotifier<List<SnChatRoom>> {
|
extends $AsyncNotifier<List<SnChatRoom>> {
|
||||||
@@ -42,7 +42,6 @@ abstract class _$ChatRoomJoinedNotifier
|
|||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build();
|
|
||||||
final ref =
|
final ref =
|
||||||
this.ref as $Ref<AsyncValue<List<SnChatRoom>>, List<SnChatRoom>>;
|
this.ref as $Ref<AsyncValue<List<SnChatRoom>>, List<SnChatRoom>>;
|
||||||
final element =
|
final element =
|
||||||
@@ -53,16 +52,16 @@ abstract class _$ChatRoomJoinedNotifier
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, build);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ProviderFor(ChatRoomNotifier)
|
@ProviderFor(ChatRoomNotifier)
|
||||||
const chatRoomProvider = ChatRoomNotifierFamily._();
|
final chatRoomProvider = ChatRoomNotifierFamily._();
|
||||||
|
|
||||||
final class ChatRoomNotifierProvider
|
final class ChatRoomNotifierProvider
|
||||||
extends $AsyncNotifierProvider<ChatRoomNotifier, SnChatRoom?> {
|
extends $AsyncNotifierProvider<ChatRoomNotifier, SnChatRoom?> {
|
||||||
const ChatRoomNotifierProvider._({
|
ChatRoomNotifierProvider._({
|
||||||
required ChatRoomNotifierFamily super.from,
|
required ChatRoomNotifierFamily super.from,
|
||||||
required String? super.argument,
|
required String? super.argument,
|
||||||
}) : super(
|
}) : super(
|
||||||
@@ -98,7 +97,7 @@ final class ChatRoomNotifierProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$chatRoomNotifierHash() => r'1e6391e2ab4eeb114fa001aaa6b06ab2bd646f38';
|
String _$chatRoomNotifierHash() => r'9f7a8bdd4af381c6b60e65e74363a0af3c1a650e';
|
||||||
|
|
||||||
final class ChatRoomNotifierFamily extends $Family
|
final class ChatRoomNotifierFamily extends $Family
|
||||||
with
|
with
|
||||||
@@ -109,7 +108,7 @@ final class ChatRoomNotifierFamily extends $Family
|
|||||||
FutureOr<SnChatRoom?>,
|
FutureOr<SnChatRoom?>,
|
||||||
String?
|
String?
|
||||||
> {
|
> {
|
||||||
const ChatRoomNotifierFamily._()
|
ChatRoomNotifierFamily._()
|
||||||
: super(
|
: super(
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'chatRoomProvider',
|
name: r'chatRoomProvider',
|
||||||
@@ -133,7 +132,6 @@ abstract class _$ChatRoomNotifier extends $AsyncNotifier<SnChatRoom?> {
|
|||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build(_$args);
|
|
||||||
final ref = this.ref as $Ref<AsyncValue<SnChatRoom?>, SnChatRoom?>;
|
final ref = this.ref as $Ref<AsyncValue<SnChatRoom?>, SnChatRoom?>;
|
||||||
final element =
|
final element =
|
||||||
ref.element
|
ref.element
|
||||||
@@ -143,16 +141,16 @@ abstract class _$ChatRoomNotifier extends $AsyncNotifier<SnChatRoom?> {
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, () => build(_$args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ProviderFor(ChatRoomIdentityNotifier)
|
@ProviderFor(ChatRoomIdentityNotifier)
|
||||||
const chatRoomIdentityProvider = ChatRoomIdentityNotifierFamily._();
|
final chatRoomIdentityProvider = ChatRoomIdentityNotifierFamily._();
|
||||||
|
|
||||||
final class ChatRoomIdentityNotifierProvider
|
final class ChatRoomIdentityNotifierProvider
|
||||||
extends $AsyncNotifierProvider<ChatRoomIdentityNotifier, SnChatMember?> {
|
extends $AsyncNotifierProvider<ChatRoomIdentityNotifier, SnChatMember?> {
|
||||||
const ChatRoomIdentityNotifierProvider._({
|
ChatRoomIdentityNotifierProvider._({
|
||||||
required ChatRoomIdentityNotifierFamily super.from,
|
required ChatRoomIdentityNotifierFamily super.from,
|
||||||
required String? super.argument,
|
required String? super.argument,
|
||||||
}) : super(
|
}) : super(
|
||||||
@@ -190,7 +188,7 @@ final class ChatRoomIdentityNotifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$chatRoomIdentityNotifierHash() =>
|
String _$chatRoomIdentityNotifierHash() =>
|
||||||
r'27c17d55366d39be81d7209837e5c01f80a68a24';
|
r'1ce75462a19cc037c97ee6084a30fee1f5335875';
|
||||||
|
|
||||||
final class ChatRoomIdentityNotifierFamily extends $Family
|
final class ChatRoomIdentityNotifierFamily extends $Family
|
||||||
with
|
with
|
||||||
@@ -201,7 +199,7 @@ final class ChatRoomIdentityNotifierFamily extends $Family
|
|||||||
FutureOr<SnChatMember?>,
|
FutureOr<SnChatMember?>,
|
||||||
String?
|
String?
|
||||||
> {
|
> {
|
||||||
const ChatRoomIdentityNotifierFamily._()
|
ChatRoomIdentityNotifierFamily._()
|
||||||
: super(
|
: super(
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'chatRoomIdentityProvider',
|
name: r'chatRoomIdentityProvider',
|
||||||
@@ -226,7 +224,6 @@ abstract class _$ChatRoomIdentityNotifier
|
|||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build(_$args);
|
|
||||||
final ref = this.ref as $Ref<AsyncValue<SnChatMember?>, SnChatMember?>;
|
final ref = this.ref as $Ref<AsyncValue<SnChatMember?>, SnChatMember?>;
|
||||||
final element =
|
final element =
|
||||||
ref.element
|
ref.element
|
||||||
@@ -236,12 +233,12 @@ abstract class _$ChatRoomIdentityNotifier
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, () => build(_$args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ProviderFor(chatroomInvites)
|
@ProviderFor(chatroomInvites)
|
||||||
const chatroomInvitesProvider = ChatroomInvitesProvider._();
|
final chatroomInvitesProvider = ChatroomInvitesProvider._();
|
||||||
|
|
||||||
final class ChatroomInvitesProvider
|
final class ChatroomInvitesProvider
|
||||||
extends
|
extends
|
||||||
@@ -253,7 +250,7 @@ final class ChatroomInvitesProvider
|
|||||||
with
|
with
|
||||||
$FutureModifier<List<SnChatMember>>,
|
$FutureModifier<List<SnChatMember>>,
|
||||||
$FutureProvider<List<SnChatMember>> {
|
$FutureProvider<List<SnChatMember>> {
|
||||||
const ChatroomInvitesProvider._()
|
ChatroomInvitesProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
@@ -279,4 +276,4 @@ final class ChatroomInvitesProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
|
String _$chatroomInvitesHash() => r'fc23231d5f111b1c3796ffae2b471384b951861a';
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ import "dart:async";
|
|||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:just_audio/just_audio.dart";
|
||||||
|
import "package:island/pods/config.dart";
|
||||||
import "package:island/models/chat.dart";
|
import "package:island/models/chat.dart";
|
||||||
import "package:island/pods/chat/chat_room.dart";
|
import "package:island/pods/chat/chat_room.dart";
|
||||||
import "package:island/pods/lifecycle.dart";
|
import "package:island/pods/lifecycle.dart";
|
||||||
import "package:island/pods/chat/messages_notifier.dart";
|
import "package:island/pods/chat/messages_notifier.dart";
|
||||||
import "package:island/pods/websocket.dart";
|
import "package:island/pods/websocket.dart";
|
||||||
|
import "package:island/talker.dart";
|
||||||
import "package:island/widgets/chat/call_button.dart";
|
import "package:island/widgets/chat/call_button.dart";
|
||||||
import "package:riverpod_annotation/riverpod_annotation.dart";
|
import "package:riverpod_annotation/riverpod_annotation.dart";
|
||||||
|
|
||||||
@@ -35,6 +38,22 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
Timer? _typingCooldownTimer;
|
Timer? _typingCooldownTimer;
|
||||||
Timer? _periodicSubscribeTimer;
|
Timer? _periodicSubscribeTimer;
|
||||||
StreamSubscription? _wsSubscription;
|
StreamSubscription? _wsSubscription;
|
||||||
|
Function? _sendMessage;
|
||||||
|
|
||||||
|
void _cleanupResources() {
|
||||||
|
if (_wsSubscription != null) {
|
||||||
|
_wsSubscription!.cancel();
|
||||||
|
_wsSubscription = null;
|
||||||
|
}
|
||||||
|
if (_typingCleanupTimer != null) {
|
||||||
|
_typingCleanupTimer!.cancel();
|
||||||
|
_typingCleanupTimer = null;
|
||||||
|
}
|
||||||
|
if (_periodicSubscribeTimer != null) {
|
||||||
|
_periodicSubscribeTimer!.cancel();
|
||||||
|
_periodicSubscribeTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<SnChatMember> build(String roomId) {
|
List<SnChatMember> build(String roomId) {
|
||||||
@@ -43,6 +62,8 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
final chatIdentityAsync = ref.watch(chatRoomIdentityProvider(roomId));
|
final chatIdentityAsync = ref.watch(chatRoomIdentityProvider(roomId));
|
||||||
_messagesNotifier = ref.watch(messagesProvider(roomId).notifier);
|
_messagesNotifier = ref.watch(messagesProvider(roomId).notifier);
|
||||||
|
|
||||||
|
_cleanupResources();
|
||||||
|
|
||||||
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
|
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -56,12 +77,14 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
|
|
||||||
// Subscribe to messages
|
// Subscribe to messages
|
||||||
final wsState = ref.read(websocketStateProvider.notifier);
|
final wsState = ref.read(websocketStateProvider.notifier);
|
||||||
wsState.sendMessage(
|
_sendMessage = wsState.sendMessage;
|
||||||
|
talker.info('[MessageSubscriber] Subscribing room $roomId');
|
||||||
|
_sendMessage!(
|
||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.subscribe',
|
type: 'messages.subscribe',
|
||||||
data: {'chat_room_id': roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'messager',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -93,70 +116,91 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
|
|
||||||
// Set up periodic subscribe timer (every 5 minutes)
|
// Set up periodic subscribe timer (every 5 minutes)
|
||||||
_periodicSubscribeTimer = Timer.periodic(const Duration(minutes: 5), (_) {
|
_periodicSubscribeTimer = Timer.periodic(const Duration(minutes: 5), (_) {
|
||||||
wsState.sendMessage(
|
_sendMessage!(
|
||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.subscribe',
|
type: 'messages.subscribe',
|
||||||
data: {'chat_room_id': roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'messager',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen to app lifecycle changes
|
|
||||||
ref.listen(appLifecycleStateProvider, (previous, next) {
|
ref.listen(appLifecycleStateProvider, (previous, next) {
|
||||||
final lifecycleState = next.value;
|
final lifecycleState = next.value;
|
||||||
if (lifecycleState == AppLifecycleState.paused ||
|
if (lifecycleState == AppLifecycleState.paused ||
|
||||||
lifecycleState == AppLifecycleState.inactive) {
|
lifecycleState == AppLifecycleState.inactive) {
|
||||||
// Unsubscribe when app goes to background
|
// Unsubscribe when app goes to background
|
||||||
final wsState = ref.read(websocketStateProvider.notifier);
|
talker.info('[MessageSubscriber] Unsubscribing room $roomId');
|
||||||
wsState.sendMessage(
|
_sendMessage!(
|
||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.unsubscribe',
|
type: 'messages.unsubscribe',
|
||||||
data: {'chat_room_id': roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'messager',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (lifecycleState == AppLifecycleState.resumed) {
|
} else if (lifecycleState == AppLifecycleState.resumed) {
|
||||||
// Resubscribe when app comes back to foreground
|
// Resubscribe when app comes back to foreground
|
||||||
final wsState = ref.read(websocketStateProvider.notifier);
|
talker.info('[MessageSubscriber] Subscribing room $roomId');
|
||||||
wsState.sendMessage(
|
_sendMessage!(
|
||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.subscribe',
|
type: 'messages.subscribe',
|
||||||
data: {'chat_room_id': roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'messager',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cleanup on dispose
|
final subscribedNotifier = ref.watch(
|
||||||
ref.onDispose(() {
|
currentSubscribedChatIdProvider.notifier,
|
||||||
ref.read(currentSubscribedChatIdProvider.notifier).set(null);
|
);
|
||||||
wsState.sendMessage(
|
|
||||||
|
ref.onCancel(() {
|
||||||
|
talker.info('[MessageSubscriber] Unsubscribing room $roomId');
|
||||||
|
subscribedNotifier.set(null);
|
||||||
|
try {
|
||||||
|
_sendMessage!(
|
||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.unsubscribe',
|
type: 'messages.unsubscribe',
|
||||||
data: {'chat_room_id': roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'messager',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
_wsSubscription?.cancel();
|
} catch (e, stackTrace) {
|
||||||
_typingCleanupTimer?.cancel();
|
talker.error(
|
||||||
_typingCooldownTimer?.cancel();
|
'[MessageSubscriber] Error sending unsubscribe message for room $roomId: $e\n$stackTrace',
|
||||||
_periodicSubscribeTimer?.cancel();
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
_cleanupResources();
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
talker.error(
|
||||||
|
'[MessageSubscriber] Error during cleanup for room $roomId: $e\n$stackTrace',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (_typingCooldownTimer != null) {
|
||||||
|
_typingCooldownTimer!.cancel();
|
||||||
|
}
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
talker.error(
|
||||||
|
'[MessageSubscriber] Error cancelling typing cooldown timer for room $roomId: $e\n$stackTrace',
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return _typingStatuses;
|
return _typingStatuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onMessage(WebSocketPacket pkt) {
|
Future<void> onMessage(WebSocketPacket pkt) async {
|
||||||
if (!pkt.type.startsWith('messages')) return;
|
if (!pkt.type.startsWith('messages')) return;
|
||||||
if (['messages.read'].contains(pkt.type)) return;
|
if (['messages.read'].contains(pkt.type)) return;
|
||||||
|
|
||||||
@@ -196,18 +240,29 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
_messagesNotifier.receiveMessage(message);
|
_messagesNotifier.receiveMessage(message);
|
||||||
// Send read receipt for new message
|
// Send read receipt for new message
|
||||||
sendReadReceipt();
|
sendReadReceipt();
|
||||||
|
// Play sound for new messages when app is unfocused
|
||||||
|
if (pkt.type == 'messages.new' &&
|
||||||
|
message.senderId != _chatIdentity.id &&
|
||||||
|
ref.read(appLifecycleStateProvider).value != AppLifecycleState.resumed &&
|
||||||
|
ref.read(appSettingsProvider).soundEffects) {
|
||||||
|
final player = AudioPlayer();
|
||||||
|
await player.setVolume(0.75);
|
||||||
|
await player.setAudioSource(AudioSource.asset('assets/audio/messages.mp3'));
|
||||||
|
await player.play();
|
||||||
|
player.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendReadReceipt() {
|
void sendReadReceipt() {
|
||||||
// Send websocket packet
|
// Send websocket packet
|
||||||
final wsState = ref.read(websocketStateProvider.notifier);
|
if (_sendMessage == null) return;
|
||||||
wsState.sendMessage(
|
_sendMessage!(
|
||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.read',
|
type: 'messages.read',
|
||||||
data: {'chat_room_id': roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'messager',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -218,13 +273,13 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
if (_typingCooldownTimer != null) return;
|
if (_typingCooldownTimer != null) return;
|
||||||
|
|
||||||
// Send typing status immediately
|
// Send typing status immediately
|
||||||
final wsState = ref.read(websocketStateProvider.notifier);
|
if (_sendMessage == null) return;
|
||||||
wsState.sendMessage(
|
_sendMessage!(
|
||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.typing',
|
type: 'messages.typing',
|
||||||
data: {'chat_room_id': roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'messager',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ part of 'chat_subscribe.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(ChatSubscribeNotifier)
|
@ProviderFor(ChatSubscribeNotifier)
|
||||||
const chatSubscribeProvider = ChatSubscribeNotifierFamily._();
|
final chatSubscribeProvider = ChatSubscribeNotifierFamily._();
|
||||||
|
|
||||||
final class ChatSubscribeNotifierProvider
|
final class ChatSubscribeNotifierProvider
|
||||||
extends $NotifierProvider<ChatSubscribeNotifier, List<SnChatMember>> {
|
extends $NotifierProvider<ChatSubscribeNotifier, List<SnChatMember>> {
|
||||||
const ChatSubscribeNotifierProvider._({
|
ChatSubscribeNotifierProvider._({
|
||||||
required ChatSubscribeNotifierFamily super.from,
|
required ChatSubscribeNotifierFamily super.from,
|
||||||
required String super.argument,
|
required String super.argument,
|
||||||
}) : super(
|
}) : super(
|
||||||
@@ -59,7 +59,7 @@ final class ChatSubscribeNotifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$chatSubscribeNotifierHash() =>
|
String _$chatSubscribeNotifierHash() =>
|
||||||
r'1aa164429aaab1628b5edbae11e33b0860abdcdc';
|
r'b7624ae45ace2944a88f8b4d14ddce556c236371';
|
||||||
|
|
||||||
final class ChatSubscribeNotifierFamily extends $Family
|
final class ChatSubscribeNotifierFamily extends $Family
|
||||||
with
|
with
|
||||||
@@ -70,7 +70,7 @@ final class ChatSubscribeNotifierFamily extends $Family
|
|||||||
List<SnChatMember>,
|
List<SnChatMember>,
|
||||||
String
|
String
|
||||||
> {
|
> {
|
||||||
const ChatSubscribeNotifierFamily._()
|
ChatSubscribeNotifierFamily._()
|
||||||
: super(
|
: super(
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'chatSubscribeProvider',
|
name: r'chatSubscribeProvider',
|
||||||
@@ -94,7 +94,6 @@ abstract class _$ChatSubscribeNotifier extends $Notifier<List<SnChatMember>> {
|
|||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build(_$args);
|
|
||||||
final ref = this.ref as $Ref<List<SnChatMember>, List<SnChatMember>>;
|
final ref = this.ref as $Ref<List<SnChatMember>, List<SnChatMember>>;
|
||||||
final element =
|
final element =
|
||||||
ref.element
|
ref.element
|
||||||
@@ -104,6 +103,6 @@ abstract class _$ChatSubscribeNotifier extends $Notifier<List<SnChatMember>> {
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, () => build(_$args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ChatUnreadCountNotifier extends _$ChatUnreadCountNotifier {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final response = await client.get('/sphere/chat/unread');
|
final response = await client.get('/messager/chat/unread');
|
||||||
return (response.data as num).toInt();
|
return (response.data as num).toInt();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -65,7 +65,7 @@ class ChatSummary extends _$ChatSummary {
|
|||||||
@override
|
@override
|
||||||
Future<Map<String, SnChatSummary>> build() async {
|
Future<Map<String, SnChatSummary>> build() async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat/summary');
|
final resp = await client.get('/messager/chat/summary');
|
||||||
|
|
||||||
final Map<String, dynamic> data = resp.data;
|
final Map<String, dynamic> data = resp.data;
|
||||||
final summaries = data.map(
|
final summaries = data.map(
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ part of 'chat_summary.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(ChatUnreadCountNotifier)
|
@ProviderFor(ChatUnreadCountNotifier)
|
||||||
const chatUnreadCountProvider = ChatUnreadCountNotifierProvider._();
|
final chatUnreadCountProvider = ChatUnreadCountNotifierProvider._();
|
||||||
|
|
||||||
final class ChatUnreadCountNotifierProvider
|
final class ChatUnreadCountNotifierProvider
|
||||||
extends $AsyncNotifierProvider<ChatUnreadCountNotifier, int> {
|
extends $AsyncNotifierProvider<ChatUnreadCountNotifier, int> {
|
||||||
const ChatUnreadCountNotifierProvider._()
|
ChatUnreadCountNotifierProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
@@ -34,14 +34,13 @@ final class ChatUnreadCountNotifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$chatUnreadCountNotifierHash() =>
|
String _$chatUnreadCountNotifierHash() =>
|
||||||
r'b8d93589dc37f772d4c3a07d9afd81c37026e57d';
|
r'169b28f8759ebd9de75f7de17f60d493737ee7a8';
|
||||||
|
|
||||||
abstract class _$ChatUnreadCountNotifier extends $AsyncNotifier<int> {
|
abstract class _$ChatUnreadCountNotifier extends $AsyncNotifier<int> {
|
||||||
FutureOr<int> build();
|
FutureOr<int> build();
|
||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build();
|
|
||||||
final ref = this.ref as $Ref<AsyncValue<int>, int>;
|
final ref = this.ref as $Ref<AsyncValue<int>, int>;
|
||||||
final element =
|
final element =
|
||||||
ref.element
|
ref.element
|
||||||
@@ -51,16 +50,16 @@ abstract class _$ChatUnreadCountNotifier extends $AsyncNotifier<int> {
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, build);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ProviderFor(ChatSummary)
|
@ProviderFor(ChatSummary)
|
||||||
const chatSummaryProvider = ChatSummaryProvider._();
|
final chatSummaryProvider = ChatSummaryProvider._();
|
||||||
|
|
||||||
final class ChatSummaryProvider
|
final class ChatSummaryProvider
|
||||||
extends $AsyncNotifierProvider<ChatSummary, Map<String, SnChatSummary>> {
|
extends $AsyncNotifierProvider<ChatSummary, Map<String, SnChatSummary>> {
|
||||||
const ChatSummaryProvider._()
|
ChatSummaryProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
@@ -79,7 +78,7 @@ final class ChatSummaryProvider
|
|||||||
ChatSummary create() => ChatSummary();
|
ChatSummary create() => ChatSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$chatSummaryHash() => r'dfa5e487586482ebdafef8d711f74db68ee86f84';
|
String _$chatSummaryHash() => r'82f516d4ce8b67dadb815523df57a3c30a33ef91';
|
||||||
|
|
||||||
abstract class _$ChatSummary
|
abstract class _$ChatSummary
|
||||||
extends $AsyncNotifier<Map<String, SnChatSummary>> {
|
extends $AsyncNotifier<Map<String, SnChatSummary>> {
|
||||||
@@ -87,7 +86,6 @@ abstract class _$ChatSummary
|
|||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build();
|
|
||||||
final ref =
|
final ref =
|
||||||
this.ref
|
this.ref
|
||||||
as $Ref<
|
as $Ref<
|
||||||
@@ -105,6 +103,6 @@ abstract class _$ChatSummary
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, build);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import "package:island/screens/account/profile.dart";
|
|||||||
|
|
||||||
part 'messages_notifier.g.dart';
|
part 'messages_notifier.g.dart';
|
||||||
|
|
||||||
|
const Set<String> kSilentMessageTypes = {'messages.update.links'};
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class MessagesNotifier extends _$MessagesNotifier {
|
class MessagesNotifier extends _$MessagesNotifier {
|
||||||
late Dio _apiClient;
|
late Dio _apiClient;
|
||||||
@@ -80,6 +82,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
if (identity != null) {
|
if (identity != null) {
|
||||||
ref.listen(appLifecycleStateProvider, (_, next) {
|
ref.listen(appLifecycleStateProvider, (_, next) {
|
||||||
next.whenData((state) {
|
next.whenData((state) {
|
||||||
|
if (!ref.mounted) return; // Check disposal before accessing ref
|
||||||
if (state == AppLifecycleState.paused) {
|
if (state == AppLifecycleState.paused) {
|
||||||
_lastPauseTime = DateTime.now();
|
_lastPauseTime = DateTime.now();
|
||||||
talker.log('App paused, recording time');
|
talker.log('App paused, recording time');
|
||||||
@@ -88,7 +91,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
final diff = DateTime.now().difference(_lastPauseTime!);
|
final diff = DateTime.now().difference(_lastPauseTime!);
|
||||||
if (diff > const Duration(minutes: 1)) {
|
if (diff > const Duration(minutes: 1)) {
|
||||||
talker.log('App resumed after >1 min, syncing messages');
|
talker.log('App resumed after >1 min, syncing messages');
|
||||||
syncMessages();
|
if (!!ref.mounted) {
|
||||||
|
syncMessages(); // Check disposal before calling syncMessages
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
talker.log('App resumed within 1 min, skipping sync');
|
talker.log('App resumed within 1 min, skipping sync');
|
||||||
}
|
}
|
||||||
@@ -123,7 +128,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
uniqueMessages.add(message);
|
uniqueMessages.add(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state = AsyncValue.data(uniqueMessages);
|
if (ref.mounted) state = AsyncValue.data(uniqueMessages);
|
||||||
} finally {
|
} finally {
|
||||||
_isUpdatingState = false;
|
_isUpdatingState = false;
|
||||||
}
|
}
|
||||||
@@ -167,13 +172,13 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
List<LocalChatMessage> filteredMessages = dbMessages;
|
List<LocalChatMessage> filteredMessages = dbMessages;
|
||||||
|
|
||||||
if (withLinks == true) {
|
if (withLinks == true) {
|
||||||
filteredMessages =
|
filteredMessages = filteredMessages
|
||||||
filteredMessages.where((msg) => _hasLink(msg)).toList();
|
.where((msg) => _hasLink(msg))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (withAttachments == true) {
|
if (withAttachments == true) {
|
||||||
filteredMessages =
|
filteredMessages = filteredMessages
|
||||||
filteredMessages
|
|
||||||
.where((msg) => msg.toRemoteMessage().attachments.isNotEmpty)
|
.where((msg) => msg.toRemoteMessage().attachments.isNotEmpty)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
@@ -190,8 +195,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
final pendingForRoom =
|
final pendingForRoom = _pendingMessages.values
|
||||||
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
.where((msg) => msg.roomId == roomId)
|
||||||
|
.toList();
|
||||||
|
|
||||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||||
_sortMessages(allMessages); // Use the helper function
|
_sortMessages(allMessages); // Use the helper function
|
||||||
@@ -239,8 +245,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
final pendingForRoom =
|
final pendingForRoom = _pendingMessages.values
|
||||||
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
.where((msg) => msg.roomId == roomId)
|
||||||
|
.toList();
|
||||||
|
|
||||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||||
_sortMessages(allMessages);
|
_sortMessages(allMessages);
|
||||||
@@ -265,7 +272,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
talker.log('Fetching messages from API, offset $offset, take $take');
|
talker.log('Fetching messages from API, offset $offset, take $take');
|
||||||
if (_totalCount == null) {
|
if (_totalCount == null) {
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$roomId/messages',
|
'/messager/chat/$roomId/messages',
|
||||||
queryParameters: {'offset': 0, 'take': 1},
|
queryParameters: {'offset': 0, 'take': 1},
|
||||||
);
|
);
|
||||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||||
@@ -277,15 +284,14 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$roomId/messages',
|
'/messager/chat/$roomId/messages',
|
||||||
queryParameters: {'offset': offset, 'take': take},
|
queryParameters: {'offset': offset, 'take': take},
|
||||||
);
|
);
|
||||||
|
|
||||||
final List<dynamic> data = response.data;
|
final List<dynamic> data = response.data;
|
||||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||||
|
|
||||||
final messages =
|
final messages = data.map((json) {
|
||||||
data.map((json) {
|
|
||||||
final remoteMessage = SnChatMessage.fromJson(json);
|
final remoteMessage = SnChatMessage.fromJson(json);
|
||||||
return LocalChatMessage.fromRemoteMessage(
|
return LocalChatMessage.fromRemoteMessage(
|
||||||
remoteMessage,
|
remoteMessage,
|
||||||
@@ -319,15 +325,19 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_allRemoteMessagesFetched = false;
|
_allRemoteMessagesFetched = false;
|
||||||
|
|
||||||
talker.log('Starting message sync');
|
talker.log('Starting message sync');
|
||||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(true));
|
// Use Future.microtask to set syncing state, but check disposal to avoid errors
|
||||||
|
Future.microtask(() {
|
||||||
|
if (!!ref.mounted) {
|
||||||
|
ref.read(chatSyncingProvider.notifier).set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
final dbMessages = await _database.getMessagesForRoom(
|
final dbMessages = await _database.getMessagesForRoom(
|
||||||
_room.id,
|
_room.id,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
);
|
);
|
||||||
final lastMessage =
|
final lastMessage = dbMessages.isEmpty
|
||||||
dbMessages.isEmpty
|
|
||||||
? null
|
? null
|
||||||
: await _database.companionToMessage(
|
: await _database.companionToMessage(
|
||||||
dbMessages.first,
|
dbMessages.first,
|
||||||
@@ -340,19 +350,21 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
take: _pageSize,
|
take: _pageSize,
|
||||||
);
|
);
|
||||||
state = AsyncValue.data(newMessages);
|
if (ref.mounted) state = AsyncValue.data(newMessages);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync with pagination support using timestamp-based cursor
|
// Sync with pagination support using timestamp-based cursor
|
||||||
int? totalMessages;
|
int? totalMessages;
|
||||||
int syncedCount = 0;
|
int syncedCount = 0;
|
||||||
int lastSyncTimestamp =
|
int lastSyncTimestamp = lastMessage
|
||||||
lastMessage.toRemoteMessage().updatedAt.millisecondsSinceEpoch;
|
.toRemoteMessage()
|
||||||
|
.updatedAt
|
||||||
|
.millisecondsSinceEpoch;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
final resp = await _apiClient.post(
|
final resp = await _apiClient.post(
|
||||||
'/sphere/chat/${_room.id}/sync',
|
'/messager/chat/${_room.id}/sync',
|
||||||
data: {'last_sync_timestamp': lastSyncTimestamp},
|
data: {'last_sync_timestamp': lastSyncTimestamp},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -395,7 +407,10 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
talker.log('Finished message sync');
|
talker.log('Finished message sync');
|
||||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(false));
|
// Always reset global syncing state, regardless of disposal
|
||||||
|
Future.microtask(() {
|
||||||
|
if (ref.mounted) ref.read(chatSyncingProvider.notifier).set(false);
|
||||||
|
});
|
||||||
_isSyncing = false;
|
_isSyncing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -485,16 +500,18 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
_hasMore = messages.length == _pageSize;
|
_hasMore = messages.length == _pageSize;
|
||||||
|
|
||||||
state = AsyncValue.data(messages);
|
if (ref.mounted) state = AsyncValue.data(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadMore() async {
|
Future<void> loadMore() async {
|
||||||
if (!_hasMore || state is AsyncLoading) return;
|
if (!_hasMore || state is AsyncLoading) return;
|
||||||
talker.log('Loading more messages');
|
talker.log('Loading more messages');
|
||||||
|
|
||||||
|
if (!!ref.mounted) {
|
||||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(true));
|
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(true));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = (ref.mounted ? state.value : null) ?? [];
|
||||||
final offset = currentMessages.length;
|
final offset = currentMessages.length;
|
||||||
|
|
||||||
final newMessages = await listMessages(offset: offset, take: _pageSize);
|
final newMessages = await listMessages(offset: offset, take: _pageSize);
|
||||||
@@ -503,9 +520,11 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_hasMore = false;
|
_hasMore = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ref.mounted) {
|
||||||
state = AsyncValue.data(
|
state = AsyncValue.data(
|
||||||
_sortMessages([...currentMessages, ...newMessages]),
|
_sortMessages([...currentMessages, ...newMessages]),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
} catch (err, stackTrace) {
|
} catch (err, stackTrace) {
|
||||||
talker.log(
|
talker.log(
|
||||||
'Error loading more messages',
|
'Error loading more messages',
|
||||||
@@ -515,12 +534,15 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
);
|
);
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(false));
|
// Always reset global syncing state, regardless of disposal
|
||||||
|
Future.microtask(() {
|
||||||
|
if (ref.mounted) ref.read(chatSyncingProvider.notifier).set(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendMessage(
|
Future<void> sendMessage(
|
||||||
WidgetRef ref,
|
WidgetRef outerRef,
|
||||||
String content,
|
String content,
|
||||||
List<UniversalFile> attachments, {
|
List<UniversalFile> attachments, {
|
||||||
SnPoll? poll,
|
SnPoll? poll,
|
||||||
@@ -553,15 +575,14 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_fileUploadProgress[localMessage.id] = {};
|
_fileUploadProgress[localMessage.id] = {};
|
||||||
await _database.saveMessageWithSender(localMessage);
|
await _database.saveMessageWithSender(localMessage);
|
||||||
|
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = (ref.mounted ? state.value : null) ?? [];
|
||||||
state = AsyncValue.data([localMessage, ...currentMessages]);
|
state = AsyncValue.data([localMessage, ...currentMessages]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var cloudAttachments = List.empty(growable: true);
|
var cloudAttachments = List.empty(growable: true);
|
||||||
for (var idx = 0; idx < attachments.length; idx++) {
|
for (var idx = 0; idx < attachments.length; idx++) {
|
||||||
final cloudFile =
|
final cloudFile = await FileUploader.createCloudFile(
|
||||||
await FileUploader.createCloudFile(
|
ref: outerRef,
|
||||||
ref: ref,
|
|
||||||
fileData: attachments[idx],
|
fileData: attachments[idx],
|
||||||
onProgress: (progress, _) {
|
onProgress: (progress, _) {
|
||||||
_fileUploadProgress[localMessage.id]?[idx] = progress ?? 0.0;
|
_fileUploadProgress[localMessage.id]?[idx] = progress ?? 0.0;
|
||||||
@@ -579,8 +600,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
final response = await _apiClient.request(
|
final response = await _apiClient.request(
|
||||||
editingTo == null
|
editingTo == null
|
||||||
? '/sphere/chat/$roomId/messages'
|
? '/messager/chat/$roomId/messages'
|
||||||
: '/sphere/chat/$roomId/messages/${editingTo.id}',
|
: '/messager/chat/$roomId/messages/${editingTo.id}',
|
||||||
data: {
|
data: {
|
||||||
'content': content,
|
'content': content,
|
||||||
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
||||||
@@ -604,10 +625,10 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
await _database.deleteMessage(localMessage.id);
|
await _database.deleteMessage(localMessage.id);
|
||||||
await _database.saveMessageWithSender(updatedMessage);
|
await _database.saveMessageWithSender(updatedMessage);
|
||||||
|
|
||||||
|
if (ref.mounted) {
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = state.value ?? [];
|
||||||
if (editingTo != null) {
|
if (editingTo != null) {
|
||||||
final newMessages =
|
final newMessages = currentMessages
|
||||||
currentMessages
|
|
||||||
.where((m) => m.id != localMessage.id) // remove pending message
|
.where((m) => m.id != localMessage.id) // remove pending message
|
||||||
.map(
|
.map(
|
||||||
(m) => m.id == editingTo.id ? updatedMessage : m,
|
(m) => m.id == editingTo.id ? updatedMessage : m,
|
||||||
@@ -615,8 +636,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
.toList();
|
.toList();
|
||||||
state = AsyncValue.data(newMessages);
|
state = AsyncValue.data(newMessages);
|
||||||
} else {
|
} else {
|
||||||
final newMessages =
|
final newMessages = currentMessages.map((m) {
|
||||||
currentMessages.map((m) {
|
|
||||||
if (m.id == localMessage.id) {
|
if (m.id == localMessage.id) {
|
||||||
return updatedMessage;
|
return updatedMessage;
|
||||||
}
|
}
|
||||||
@@ -624,6 +644,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}).toList();
|
}).toList();
|
||||||
state = AsyncValue.data(newMessages);
|
state = AsyncValue.data(newMessages);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
talker.log('Message with nonce $nonce sent successfully');
|
talker.log('Message with nonce $nonce sent successfully');
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
talker.log(
|
talker.log(
|
||||||
@@ -638,14 +660,15 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
localMessage.id,
|
localMessage.id,
|
||||||
MessageStatus.failed,
|
MessageStatus.failed,
|
||||||
);
|
);
|
||||||
final newMessages =
|
if (ref.mounted) {
|
||||||
(state.value ?? []).map((m) {
|
final newMessages = (state.value ?? []).map((m) {
|
||||||
if (m.id == localMessage.id) {
|
if (m.id == localMessage.id) {
|
||||||
return m..status = MessageStatus.failed;
|
return m..status = MessageStatus.failed;
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}).toList();
|
}).toList();
|
||||||
state = AsyncValue.data(newMessages);
|
state = AsyncValue.data(newMessages);
|
||||||
|
}
|
||||||
showErrorAlert(e);
|
showErrorAlert(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -667,7 +690,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
try {
|
try {
|
||||||
var remoteMessage = message.toRemoteMessage();
|
var remoteMessage = message.toRemoteMessage();
|
||||||
final response = await _apiClient.post(
|
final response = await _apiClient.post(
|
||||||
'/sphere/chat/${message.roomId}/messages',
|
'/messager/chat/${message.roomId}/messages',
|
||||||
data: {
|
data: {
|
||||||
'content': remoteMessage.content,
|
'content': remoteMessage.content,
|
||||||
'attachments_id': remoteMessage.attachments,
|
'attachments_id': remoteMessage.attachments,
|
||||||
@@ -686,14 +709,15 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
await _database.deleteMessage(pendingMessageId);
|
await _database.deleteMessage(pendingMessageId);
|
||||||
await _database.saveMessageWithSender(updatedMessage);
|
await _database.saveMessageWithSender(updatedMessage);
|
||||||
|
|
||||||
final newMessages =
|
if (ref.mounted) {
|
||||||
(state.value ?? []).map((m) {
|
final newMessages = (state.value ?? []).map((m) {
|
||||||
if (m.id == pendingMessageId) {
|
if (m.id == pendingMessageId) {
|
||||||
return updatedMessage;
|
return updatedMessage;
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}).toList();
|
}).toList();
|
||||||
state = AsyncValue.data(newMessages);
|
state = AsyncValue.data(newMessages);
|
||||||
|
}
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
talker.log(
|
talker.log(
|
||||||
'Failed to retry message $pendingMessageId',
|
'Failed to retry message $pendingMessageId',
|
||||||
@@ -707,14 +731,15 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
pendingMessageId,
|
pendingMessageId,
|
||||||
MessageStatus.failed,
|
MessageStatus.failed,
|
||||||
);
|
);
|
||||||
final newMessages =
|
if (ref.mounted) {
|
||||||
(state.value ?? []).map((m) {
|
final newMessages = (state.value ?? []).map((m) {
|
||||||
if (m.id == pendingMessageId) {
|
if (m.id == pendingMessageId) {
|
||||||
return m..status = MessageStatus.failed;
|
return m..status = MessageStatus.failed;
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}).toList();
|
}).toList();
|
||||||
state = AsyncValue.data(_sortMessages(newMessages));
|
state = AsyncValue.data(_sortMessages(newMessages));
|
||||||
|
}
|
||||||
showErrorAlert(e);
|
showErrorAlert(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -730,6 +755,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
talker.log('Received new message ${remoteMessage.id}');
|
talker.log('Received new message ${remoteMessage.id}');
|
||||||
|
|
||||||
|
final isSilentMessage = kSilentMessageTypes.contains(remoteMessage.type);
|
||||||
|
|
||||||
final localMessage = LocalChatMessage.fromRemoteMessage(
|
final localMessage = LocalChatMessage.fromRemoteMessage(
|
||||||
remoteMessage,
|
remoteMessage,
|
||||||
MessageStatus.sent,
|
MessageStatus.sent,
|
||||||
@@ -741,15 +768,17 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isSilentMessage) {
|
||||||
await _database.saveMessageWithSender(localMessage);
|
await _database.saveMessageWithSender(localMessage);
|
||||||
|
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = (ref.mounted ? state.value : null) ?? [];
|
||||||
final existingIndex = currentMessages.indexWhere(
|
final existingIndex = currentMessages.indexWhere(
|
||||||
(m) =>
|
(m) =>
|
||||||
m.id == localMessage.id ||
|
m.id == localMessage.id ||
|
||||||
(localMessage.nonce != null && m.nonce == localMessage.nonce),
|
(localMessage.nonce != null && m.nonce == localMessage.nonce),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (ref.mounted) {
|
||||||
if (existingIndex >= 0) {
|
if (existingIndex >= 0) {
|
||||||
final newList = [...currentMessages];
|
final newList = [...currentMessages];
|
||||||
newList[existingIndex] = localMessage;
|
newList[existingIndex] = localMessage;
|
||||||
@@ -759,6 +788,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_sortMessages([localMessage, ...currentMessages]),
|
_sortMessages([localMessage, ...currentMessages]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (remoteMessage.type) {
|
switch (remoteMessage.type) {
|
||||||
case "messages.delete":
|
case "messages.delete":
|
||||||
@@ -783,7 +814,34 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
talker.log('Received message update ${remoteMessage.id}');
|
talker.log('Received message update ${remoteMessage.id}');
|
||||||
|
|
||||||
final targetId = remoteMessage.meta['message_id'] ?? remoteMessage.id;
|
final targetId = remoteMessage.meta['message_id'] ?? remoteMessage.id;
|
||||||
final updatedMessage = LocalChatMessage.fromRemoteMessage(
|
|
||||||
|
LocalChatMessage updatedMessage;
|
||||||
|
|
||||||
|
if (remoteMessage.type == 'messages.update.links') {
|
||||||
|
// For link updates, merge meta with existing message instead of creating new one
|
||||||
|
final existingMessage = await fetchMessageById(targetId);
|
||||||
|
if (existingMessage == null) {
|
||||||
|
talker.log('Cannot update links for non-existent message $targetId');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final existingRemote = existingMessage.toRemoteMessage();
|
||||||
|
final mergedMeta = Map<String, dynamic>.of(existingRemote.meta);
|
||||||
|
mergedMeta.addAll(remoteMessage.meta);
|
||||||
|
mergedMeta.remove('message_id'); // Remove the target message ID from meta
|
||||||
|
|
||||||
|
final updatedRemote = existingRemote.copyWith(
|
||||||
|
meta: mergedMeta,
|
||||||
|
editedAt: remoteMessage.createdAt,
|
||||||
|
);
|
||||||
|
|
||||||
|
updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||||
|
updatedRemote,
|
||||||
|
existingMessage.status,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// For regular updates, create new message as before
|
||||||
|
updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||||
remoteMessage.copyWith(
|
remoteMessage.copyWith(
|
||||||
id: targetId,
|
id: targetId,
|
||||||
meta: Map.of(remoteMessage.meta)..remove('message_id'),
|
meta: Map.of(remoteMessage.meta)..remove('message_id'),
|
||||||
@@ -792,17 +850,21 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
),
|
),
|
||||||
MessageStatus.sent,
|
MessageStatus.sent,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await _database.updateMessage(_database.messageToCompanion(updatedMessage));
|
await _database.updateMessage(_database.messageToCompanion(updatedMessage));
|
||||||
|
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = (ref.mounted ? state.value : null) ?? [];
|
||||||
final index = currentMessages.indexWhere((m) => m.id == updatedMessage.id);
|
final index = currentMessages.indexWhere((m) => m.id == updatedMessage.id);
|
||||||
|
|
||||||
|
if (ref.mounted) {
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
final newList = [...currentMessages];
|
final newList = [...currentMessages];
|
||||||
newList[index] = updatedMessage;
|
newList[index] = updatedMessage;
|
||||||
state = AsyncValue.data(_sortMessages(newList));
|
state = AsyncValue.data(_sortMessages(newList));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> receiveMessageDeletion(String messageId) async {
|
Future<void> receiveMessageDeletion(String messageId) async {
|
||||||
// Block message deletions during jumps to prevent list resets
|
// Block message deletions during jumps to prevent list resets
|
||||||
@@ -814,7 +876,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
talker.log('Received message deletion $messageId');
|
talker.log('Received message deletion $messageId');
|
||||||
_pendingMessages.remove(messageId);
|
_pendingMessages.remove(messageId);
|
||||||
|
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = (ref.mounted ? state.value : null) ?? [];
|
||||||
final messageIndex = currentMessages.indexWhere((m) => m.id == messageId);
|
final messageIndex = currentMessages.indexWhere((m) => m.id == messageId);
|
||||||
|
|
||||||
LocalChatMessage? messageToUpdate;
|
LocalChatMessage? messageToUpdate;
|
||||||
@@ -840,12 +902,14 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
await _database.saveMessageWithSender(deletedMessage);
|
await _database.saveMessageWithSender(deletedMessage);
|
||||||
|
|
||||||
|
if (ref.mounted) {
|
||||||
if (messageIndex != -1) {
|
if (messageIndex != -1) {
|
||||||
final newList = [...currentMessages];
|
final newList = [...currentMessages];
|
||||||
newList[messageIndex] = deletedMessage;
|
newList[messageIndex] = deletedMessage;
|
||||||
state = AsyncValue.data(newList);
|
state = AsyncValue.data(newList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> deleteMessage(String messageId) async {
|
Future<void> deleteMessage(String messageId) async {
|
||||||
talker.log('Deleting message $messageId');
|
talker.log('Deleting message $messageId');
|
||||||
@@ -864,15 +928,16 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_pendingMessages.remove(messageId);
|
_pendingMessages.remove(messageId);
|
||||||
await _database.deleteMessage(messageId);
|
await _database.deleteMessage(messageId);
|
||||||
|
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = (ref.mounted ? state.value : null) ?? [];
|
||||||
final newMessages =
|
final newMessages = currentMessages
|
||||||
currentMessages.where((m) => m.id != messageId).toList();
|
.where((m) => m.id != messageId)
|
||||||
|
.toList();
|
||||||
state = AsyncValue.data(newMessages);
|
state = AsyncValue.data(newMessages);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _apiClient.delete('/sphere/chat/$roomId/messages/$messageId');
|
await _apiClient.delete('/messager/chat/$roomId/messages/$messageId');
|
||||||
await receiveMessageDeletion(messageId);
|
await receiveMessageDeletion(messageId);
|
||||||
} catch (err, stackTrace) {
|
} catch (err, stackTrace) {
|
||||||
talker.log(
|
talker.log(
|
||||||
@@ -969,9 +1034,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
Future<LocalChatMessage?> fetchMessageById(String messageId) async {
|
Future<LocalChatMessage?> fetchMessageById(String messageId) async {
|
||||||
talker.log('Fetching message by id $messageId');
|
talker.log('Fetching message by id $messageId');
|
||||||
try {
|
try {
|
||||||
final localMessage =
|
final localMessage = await (_database.select(
|
||||||
await (_database.select(_database.chatMessages)
|
_database.chatMessages,
|
||||||
..where((tbl) => tbl.id.equals(messageId))).getSingleOrNull();
|
)..where((tbl) => tbl.id.equals(messageId))).getSingleOrNull();
|
||||||
if (localMessage != null) {
|
if (localMessage != null) {
|
||||||
return _database.companionToMessage(
|
return _database.companionToMessage(
|
||||||
localMessage,
|
localMessage,
|
||||||
@@ -980,7 +1045,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$roomId/messages/$messageId',
|
'/messager/chat/$roomId/messages/$messageId',
|
||||||
);
|
);
|
||||||
final remoteMessage = SnChatMessage.fromJson(response.data);
|
final remoteMessage = SnChatMessage.fromJson(response.data);
|
||||||
final message = LocalChatMessage.fromRemoteMessage(
|
final message = LocalChatMessage.fromRemoteMessage(
|
||||||
@@ -1005,7 +1070,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_isJumping = true;
|
_isJumping = true;
|
||||||
|
|
||||||
// Clear flashing messages when starting a new jump
|
// Clear flashing messages when starting a new jump
|
||||||
|
if (!!ref.mounted) {
|
||||||
ref.read(flashingMessagesProvider.notifier).state = {};
|
ref.read(flashingMessagesProvider.notifier).state = {};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
talker.log('Fetching message $messageId');
|
talker.log('Fetching message $messageId');
|
||||||
@@ -1017,7 +1084,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if message is already in current state to avoid duplicate loading
|
// Check if message is already in current state to avoid duplicate loading
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = (ref.mounted ? state.value : null) ?? [];
|
||||||
final existingIndex = currentMessages.indexWhere(
|
final existingIndex = currentMessages.indexWhere(
|
||||||
(m) => m.id == messageId,
|
(m) => m.id == messageId,
|
||||||
);
|
);
|
||||||
@@ -1047,8 +1114,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
// Calculate offset to position target message in the middle of the loaded chunk
|
// Calculate offset to position target message in the middle of the loaded chunk
|
||||||
const chunkSize = 100; // Load 100 messages around the target
|
const chunkSize = 100; // Load 100 messages around the target
|
||||||
final offset =
|
final offset = (newerCount - chunkSize ~/ 2)
|
||||||
(newerCount - chunkSize ~/ 2).clamp(0, double.infinity).toInt();
|
.clamp(0, double.infinity)
|
||||||
|
.toInt();
|
||||||
talker.log(
|
talker.log(
|
||||||
'Calculated offset $offset for target message (newer: $newerCount, chunk: $chunkSize)',
|
'Calculated offset $offset for target message (newer: $newerCount, chunk: $chunkSize)',
|
||||||
);
|
);
|
||||||
@@ -1060,8 +1128,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
// Check if loaded messages are already in current state
|
// Check if loaded messages are already in current state
|
||||||
final currentIds = currentMessages.map((m) => m.id).toSet();
|
final currentIds = currentMessages.map((m) => m.id).toSet();
|
||||||
final newMessages =
|
final newMessages = loadedMessages
|
||||||
loadedMessages.where((m) => !currentIds.contains(m.id)).toList();
|
.where((m) => !currentIds.contains(m.id))
|
||||||
|
.toList();
|
||||||
talker.log(
|
talker.log(
|
||||||
'Loaded ${loadedMessages.length} messages, ${newMessages.length} are new',
|
'Loaded ${loadedMessages.length} messages, ${newMessages.length} are new',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ part of 'messages_notifier.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(MessagesNotifier)
|
@ProviderFor(MessagesNotifier)
|
||||||
const messagesProvider = MessagesNotifierFamily._();
|
final messagesProvider = MessagesNotifierFamily._();
|
||||||
|
|
||||||
final class MessagesNotifierProvider
|
final class MessagesNotifierProvider
|
||||||
extends $AsyncNotifierProvider<MessagesNotifier, List<LocalChatMessage>> {
|
extends $AsyncNotifierProvider<MessagesNotifier, List<LocalChatMessage>> {
|
||||||
const MessagesNotifierProvider._({
|
MessagesNotifierProvider._({
|
||||||
required MessagesNotifierFamily super.from,
|
required MessagesNotifierFamily super.from,
|
||||||
required String super.argument,
|
required String super.argument,
|
||||||
}) : super(
|
}) : super(
|
||||||
@@ -50,7 +50,7 @@ final class MessagesNotifierProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$messagesNotifierHash() => r'2f3f19cb99357184e82d66e74a31863fcfc48856';
|
String _$messagesNotifierHash() => r'622fed0908eb04381a971e36540c516743246dff';
|
||||||
|
|
||||||
final class MessagesNotifierFamily extends $Family
|
final class MessagesNotifierFamily extends $Family
|
||||||
with
|
with
|
||||||
@@ -61,7 +61,7 @@ final class MessagesNotifierFamily extends $Family
|
|||||||
FutureOr<List<LocalChatMessage>>,
|
FutureOr<List<LocalChatMessage>>,
|
||||||
String
|
String
|
||||||
> {
|
> {
|
||||||
const MessagesNotifierFamily._()
|
MessagesNotifierFamily._()
|
||||||
: super(
|
: super(
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'messagesProvider',
|
name: r'messagesProvider',
|
||||||
@@ -86,7 +86,6 @@ abstract class _$MessagesNotifier
|
|||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build(_$args);
|
|
||||||
final ref =
|
final ref =
|
||||||
this.ref
|
this.ref
|
||||||
as $Ref<AsyncValue<List<LocalChatMessage>>, List<LocalChatMessage>>;
|
as $Ref<AsyncValue<List<LocalChatMessage>>, List<LocalChatMessage>>;
|
||||||
@@ -101,6 +100,6 @@ abstract class _$MessagesNotifier
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, () => build(_$args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:island/services/analytics_service.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
@@ -33,7 +34,6 @@ const kAppDefaultPoolId = 'app_default_pool_id';
|
|||||||
const kAppMessageDisplayStyle = 'app_message_display_style';
|
const kAppMessageDisplayStyle = 'app_message_display_style';
|
||||||
const kAppThemeMode = 'app_theme_mode';
|
const kAppThemeMode = 'app_theme_mode';
|
||||||
const kAppDisableAnimation = 'app_disable_animation';
|
const kAppDisableAnimation = 'app_disable_animation';
|
||||||
const kAppFabPosition = 'app_fab_position';
|
|
||||||
const kAppGroupedChatList = 'app_grouped_chat_list';
|
const kAppGroupedChatList = 'app_grouped_chat_list';
|
||||||
const kFeaturedPostsCollapsedId =
|
const kFeaturedPostsCollapsedId =
|
||||||
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
||||||
@@ -41,6 +41,7 @@ const kAppFirstLaunchAt = 'app_first_launch_at';
|
|||||||
const kAppAskedReview = 'app_asked_review';
|
const kAppAskedReview = 'app_asked_review';
|
||||||
const kAppDashSearchEngine = 'app_dash_search_engine';
|
const kAppDashSearchEngine = 'app_dash_search_engine';
|
||||||
const kAppDefaultScreen = 'app_default_screen';
|
const kAppDefaultScreen = 'app_default_screen';
|
||||||
|
const kAppShowFediverseContent = 'app_show_fediverse_content';
|
||||||
|
|
||||||
// Will be overrided by the ProviderScope
|
// Will be overrided by the ProviderScope
|
||||||
final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
|
final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
|
||||||
@@ -87,12 +88,12 @@ sealed class AppSettings with _$AppSettings {
|
|||||||
required String messageDisplayStyle,
|
required String messageDisplayStyle,
|
||||||
required String? themeMode,
|
required String? themeMode,
|
||||||
required bool disableAnimation,
|
required bool disableAnimation,
|
||||||
required String fabPosition,
|
|
||||||
required bool groupedChatList,
|
required bool groupedChatList,
|
||||||
required String? firstLaunchAt,
|
required String? firstLaunchAt,
|
||||||
required bool askedReview,
|
required bool askedReview,
|
||||||
required String? dashSearchEngine,
|
required String? dashSearchEngine,
|
||||||
required String? defaultScreen,
|
required String? defaultScreen,
|
||||||
|
required bool showFediverseContent,
|
||||||
}) = _AppSettings;
|
}) = _AppSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,12 +120,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
messageDisplayStyle: prefs.getString(kAppMessageDisplayStyle) ?? 'bubble',
|
messageDisplayStyle: prefs.getString(kAppMessageDisplayStyle) ?? 'bubble',
|
||||||
themeMode: prefs.getString(kAppThemeMode) ?? 'system',
|
themeMode: prefs.getString(kAppThemeMode) ?? 'system',
|
||||||
disableAnimation: prefs.getBool(kAppDisableAnimation) ?? false,
|
disableAnimation: prefs.getBool(kAppDisableAnimation) ?? false,
|
||||||
fabPosition: prefs.getString(kAppFabPosition) ?? 'center',
|
|
||||||
groupedChatList: prefs.getBool(kAppGroupedChatList) ?? false,
|
groupedChatList: prefs.getBool(kAppGroupedChatList) ?? false,
|
||||||
askedReview: prefs.getBool(kAppAskedReview) ?? false,
|
askedReview: prefs.getBool(kAppAskedReview) ?? false,
|
||||||
firstLaunchAt: prefs.getString(kAppFirstLaunchAt),
|
firstLaunchAt: prefs.getString(kAppFirstLaunchAt),
|
||||||
dashSearchEngine: prefs.getString(kAppDashSearchEngine),
|
dashSearchEngine: prefs.getString(kAppDashSearchEngine),
|
||||||
defaultScreen: prefs.getString(kAppDefaultScreen),
|
defaultScreen: prefs.getString(kAppDefaultScreen),
|
||||||
|
showFediverseContent: prefs.getBool(kAppShowFediverseContent) ?? true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,8 +257,11 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
|
|
||||||
void setThemeMode(String value) {
|
void setThemeMode(String value) {
|
||||||
final prefs = ref.read(sharedPreferencesProvider);
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
|
final oldValue = state.themeMode;
|
||||||
prefs.setString(kAppThemeMode, value);
|
prefs.setString(kAppThemeMode, value);
|
||||||
state = state.copyWith(themeMode: value);
|
state = state.copyWith(themeMode: value);
|
||||||
|
|
||||||
|
AnalyticsService().logThemeChanged(oldValue ?? 'system', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAppTransparentBackground(double value) {
|
void setAppTransparentBackground(double value) {
|
||||||
@@ -283,12 +287,6 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
state = state.copyWith(disableAnimation: value);
|
state = state.copyWith(disableAnimation: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFabPosition(String value) {
|
|
||||||
final prefs = ref.read(sharedPreferencesProvider);
|
|
||||||
prefs.setString(kAppFabPosition, value);
|
|
||||||
state = state.copyWith(fabPosition: value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setGroupedChatList(bool value) {
|
void setGroupedChatList(bool value) {
|
||||||
final prefs = ref.read(sharedPreferencesProvider);
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
prefs.setBool(kAppGroupedChatList, value);
|
prefs.setBool(kAppGroupedChatList, value);
|
||||||
@@ -320,6 +318,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
}
|
}
|
||||||
state = state.copyWith(dashSearchEngine: value);
|
state = state.copyWith(dashSearchEngine: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setShowFediverseContent(bool value) {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
|
prefs.setBool(kAppShowFediverseContent, value);
|
||||||
|
state = state.copyWith(showFediverseContent: value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final updateInfoProvider =
|
final updateInfoProvider =
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ mixin _$AppSettings {
|
|||||||
ThemeColors? get customColors; Size? get windowSize;// The window size for desktop platforms
|
ThemeColors? get customColors; Size? get windowSize;// The window size for desktop platforms
|
||||||
double get windowOpacity;// The window opacity for desktop platforms
|
double get windowOpacity;// The window opacity for desktop platforms
|
||||||
double get cardTransparency;// The card background opacity
|
double get cardTransparency;// The card background opacity
|
||||||
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get disableAnimation; String get fabPosition; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine; String? get defaultScreen;
|
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get disableAnimation; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine; String? get defaultScreen; bool get showFediverseContent;
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -301,16 +301,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen)&&(identical(other.showFediverseContent, showFediverseContent) || other.showFediverseContent == showFediverseContent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
|
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen,showFediverseContent]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
|
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen, showFediverseContent: $showFediverseContent)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
|
|||||||
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
|
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ class _$AppSettingsCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,Object? showFediverseContent = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -357,13 +357,13 @@ as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaul
|
|||||||
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
||||||
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
as String?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
as bool,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||||
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,showFediverseContent: null == showFediverseContent ? _self.showFediverseContent : showFediverseContent // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
@@ -457,10 +457,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
|
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -478,10 +478,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings():
|
case _AppSettings():
|
||||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);}
|
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -495,10 +495,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
|
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -510,7 +510,7 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
|||||||
|
|
||||||
|
|
||||||
class _AppSettings implements AppSettings {
|
class _AppSettings implements AppSettings {
|
||||||
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.disableAnimation, required this.fabPosition, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine, required this.defaultScreen});
|
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.disableAnimation, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine, required this.defaultScreen, required this.showFediverseContent});
|
||||||
|
|
||||||
|
|
||||||
@override final bool dataSavingMode;
|
@override final bool dataSavingMode;
|
||||||
@@ -534,12 +534,12 @@ class _AppSettings implements AppSettings {
|
|||||||
@override final String messageDisplayStyle;
|
@override final String messageDisplayStyle;
|
||||||
@override final String? themeMode;
|
@override final String? themeMode;
|
||||||
@override final bool disableAnimation;
|
@override final bool disableAnimation;
|
||||||
@override final String fabPosition;
|
|
||||||
@override final bool groupedChatList;
|
@override final bool groupedChatList;
|
||||||
@override final String? firstLaunchAt;
|
@override final String? firstLaunchAt;
|
||||||
@override final bool askedReview;
|
@override final bool askedReview;
|
||||||
@override final String? dashSearchEngine;
|
@override final String? dashSearchEngine;
|
||||||
@override final String? defaultScreen;
|
@override final String? defaultScreen;
|
||||||
|
@override final bool showFediverseContent;
|
||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@@ -551,16 +551,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen)&&(identical(other.showFediverseContent, showFediverseContent) || other.showFediverseContent == showFediverseContent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
|
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen,showFediverseContent]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
|
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen, showFediverseContent: $showFediverseContent)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -571,7 +571,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
|
|||||||
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
|
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -588,7 +588,7 @@ class __$AppSettingsCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,Object? showFediverseContent = null,}) {
|
||||||
return _then(_AppSettings(
|
return _then(_AppSettings(
|
||||||
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -607,13 +607,13 @@ as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaul
|
|||||||
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
||||||
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
as String?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
as bool,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||||
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,showFediverseContent: null == showFediverseContent ? _self.showFediverseContent : showFediverseContent // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ Map<String, dynamic> _$ThemeColorsToJson(_ThemeColors instance) =>
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(AppSettingsNotifier)
|
@ProviderFor(AppSettingsNotifier)
|
||||||
const appSettingsProvider = AppSettingsNotifierProvider._();
|
final appSettingsProvider = AppSettingsNotifierProvider._();
|
||||||
|
|
||||||
final class AppSettingsNotifierProvider
|
final class AppSettingsNotifierProvider
|
||||||
extends $NotifierProvider<AppSettingsNotifier, AppSettings> {
|
extends $NotifierProvider<AppSettingsNotifier, AppSettings> {
|
||||||
const AppSettingsNotifierProvider._()
|
AppSettingsNotifierProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
@@ -65,14 +65,13 @@ final class AppSettingsNotifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$appSettingsNotifierHash() =>
|
String _$appSettingsNotifierHash() =>
|
||||||
r'ef10d95a9f22e891ad6f5e0225e31508b3eb038e';
|
r'64cf6dfda90fc634336d96bd5313b2a07b19eccb';
|
||||||
|
|
||||||
abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
|
abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
|
||||||
AppSettings build();
|
AppSettings build();
|
||||||
@$mustCallSuper
|
@$mustCallSuper
|
||||||
@override
|
@override
|
||||||
void runBuild() {
|
void runBuild() {
|
||||||
final created = build();
|
|
||||||
final ref = this.ref as $Ref<AppSettings, AppSettings>;
|
final ref = this.ref as $Ref<AppSettings, AppSettings>;
|
||||||
final element =
|
final element =
|
||||||
ref.element
|
ref.element
|
||||||
@@ -82,6 +81,6 @@ abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
|
|||||||
Object?,
|
Object?,
|
||||||
Object?
|
Object?
|
||||||
>;
|
>;
|
||||||
element.handleValue(ref, created);
|
element.handleCreate(ref, build);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ final indexedCloudFileListProvider = AsyncNotifierProvider.autoDispose(
|
|||||||
IndexedCloudFileListNotifier.new,
|
IndexedCloudFileListNotifier.new,
|
||||||
);
|
);
|
||||||
|
|
||||||
class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
class IndexedCloudFileListNotifier
|
||||||
|
extends AsyncNotifier<PaginationState<FileListItem>>
|
||||||
with AsyncPaginationController<FileListItem> {
|
with AsyncPaginationController<FileListItem> {
|
||||||
String _currentPath = '/';
|
String _currentPath = '/';
|
||||||
String? _poolId;
|
String? _poolId;
|
||||||
@@ -51,6 +52,19 @@ class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
|||||||
ref.invalidateSelf();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<PaginationState<FileListItem>> build() async {
|
||||||
|
final items = await fetch();
|
||||||
|
return PaginationState(
|
||||||
|
items: items,
|
||||||
|
isLoading: false,
|
||||||
|
isReloading: false,
|
||||||
|
totalCount: null,
|
||||||
|
hasMore: false,
|
||||||
|
cursor: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<FileListItem>> fetch() async {
|
Future<List<FileListItem>> fetch() async {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
@@ -96,7 +110,8 @@ final unindexedFileListProvider = AsyncNotifierProvider.autoDispose(
|
|||||||
UnindexedFileListNotifier.new,
|
UnindexedFileListNotifier.new,
|
||||||
);
|
);
|
||||||
|
|
||||||
class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
class UnindexedFileListNotifier
|
||||||
|
extends AsyncNotifier<PaginationState<FileListItem>>
|
||||||
with AsyncPaginationController<FileListItem> {
|
with AsyncPaginationController<FileListItem> {
|
||||||
String? _poolId;
|
String? _poolId;
|
||||||
bool _recycled = false;
|
bool _recycled = false;
|
||||||
@@ -131,6 +146,19 @@ class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
|||||||
|
|
||||||
static const int pageSize = 20;
|
static const int pageSize = 20;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<PaginationState<FileListItem>> build() async {
|
||||||
|
final items = await fetch();
|
||||||
|
return PaginationState(
|
||||||
|
items: items,
|
||||||
|
isLoading: false,
|
||||||
|
isReloading: false,
|
||||||
|
totalCount: totalCount,
|
||||||
|
hasMore: hasMore,
|
||||||
|
cursor: cursor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<FileListItem>> fetch() async {
|
Future<List<FileListItem>> fetch() async {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ part of 'file_list.dart';
|
|||||||
// ignore_for_file: type=lint, type=warning
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
@ProviderFor(billingUsage)
|
@ProviderFor(billingUsage)
|
||||||
const billingUsageProvider = BillingUsageProvider._();
|
final billingUsageProvider = BillingUsageProvider._();
|
||||||
|
|
||||||
final class BillingUsageProvider
|
final class BillingUsageProvider
|
||||||
extends
|
extends
|
||||||
@@ -22,7 +22,7 @@ final class BillingUsageProvider
|
|||||||
with
|
with
|
||||||
$FutureModifier<Map<String, dynamic>?>,
|
$FutureModifier<Map<String, dynamic>?>,
|
||||||
$FutureProvider<Map<String, dynamic>?> {
|
$FutureProvider<Map<String, dynamic>?> {
|
||||||
const BillingUsageProvider._()
|
BillingUsageProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
@@ -51,7 +51,7 @@ final class BillingUsageProvider
|
|||||||
String _$billingUsageHash() => r'58d8bc774868d60781574c85d6b25869a79c57aa';
|
String _$billingUsageHash() => r'58d8bc774868d60781574c85d6b25869a79c57aa';
|
||||||
|
|
||||||
@ProviderFor(billingQuota)
|
@ProviderFor(billingQuota)
|
||||||
const billingQuotaProvider = BillingQuotaProvider._();
|
final billingQuotaProvider = BillingQuotaProvider._();
|
||||||
|
|
||||||
final class BillingQuotaProvider
|
final class BillingQuotaProvider
|
||||||
extends
|
extends
|
||||||
@@ -63,7 +63,7 @@ final class BillingQuotaProvider
|
|||||||
with
|
with
|
||||||
$FutureModifier<Map<String, dynamic>?>,
|
$FutureModifier<Map<String, dynamic>?>,
|
||||||
$FutureProvider<Map<String, dynamic>?> {
|
$FutureProvider<Map<String, dynamic>?> {
|
||||||
const BillingQuotaProvider._()
|
BillingQuotaProvider._()
|
||||||
: super(
|
: super(
|
||||||
from: null,
|
from: null,
|
||||||
argument: null,
|
argument: null,
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
import 'package:island/models/reference.dart';
|
|
||||||
import 'package:island/pods/network.dart';
|
|
||||||
|
|
||||||
part 'file_references.g.dart';
|
|
||||||
|
|
||||||
@riverpod
|
|
||||||
Future<List<Reference>> fileReferences(Ref ref, String fileId) async {
|
|
||||||
final client = ref.read(apiClientProvider);
|
|
||||||
final response = await client.get('/drive/files/$fileId/references');
|
|
||||||
final list = response.data as List<dynamic>;
|
|
||||||
return list
|
|
||||||
.map((json) => Reference.fromJson(json as Map<String, dynamic>))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'file_references.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint, type=warning
|
|
||||||
|
|
||||||
@ProviderFor(fileReferences)
|
|
||||||
const fileReferencesProvider = FileReferencesFamily._();
|
|
||||||
|
|
||||||
final class FileReferencesProvider
|
|
||||||
extends
|
|
||||||
$FunctionalProvider<
|
|
||||||
AsyncValue<List<Reference>>,
|
|
||||||
List<Reference>,
|
|
||||||
FutureOr<List<Reference>>
|
|
||||||
>
|
|
||||||
with $FutureModifier<List<Reference>>, $FutureProvider<List<Reference>> {
|
|
||||||
const FileReferencesProvider._({
|
|
||||||
required FileReferencesFamily super.from,
|
|
||||||
required String super.argument,
|
|
||||||
}) : super(
|
|
||||||
retry: null,
|
|
||||||
name: r'fileReferencesProvider',
|
|
||||||
isAutoDispose: true,
|
|
||||||
dependencies: null,
|
|
||||||
$allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String debugGetCreateSourceHash() => _$fileReferencesHash();
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return r'fileReferencesProvider'
|
|
||||||
''
|
|
||||||
'($argument)';
|
|
||||||
}
|
|
||||||
|
|
||||||
@$internal
|
|
||||||
@override
|
|
||||||
$FutureProviderElement<List<Reference>> $createElement(
|
|
||||||
$ProviderPointer pointer,
|
|
||||||
) => $FutureProviderElement(pointer);
|
|
||||||
|
|
||||||
@override
|
|
||||||
FutureOr<List<Reference>> create(Ref ref) {
|
|
||||||
final argument = this.argument as String;
|
|
||||||
return fileReferences(ref, argument);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is FileReferencesProvider && other.argument == argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
return argument.hashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$fileReferencesHash() => r'd66c678c221f61978bdb242b98e6dbe31d0c204b';
|
|
||||||
|
|
||||||
final class FileReferencesFamily extends $Family
|
|
||||||
with $FunctionalFamilyOverride<FutureOr<List<Reference>>, String> {
|
|
||||||
const FileReferencesFamily._()
|
|
||||||
: super(
|
|
||||||
retry: null,
|
|
||||||
name: r'fileReferencesProvider',
|
|
||||||
dependencies: null,
|
|
||||||
$allTransitiveDependencies: null,
|
|
||||||
isAutoDispose: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
FileReferencesProvider call(String fileId) =>
|
|
||||||
FileReferencesProvider._(argument: fileId, from: this);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => r'fileReferencesProvider';
|
|
||||||
}
|
|
||||||
@@ -29,30 +29,59 @@ class UploadTasksNotifier extends Notifier<List<DriveTask>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleWebSocketPacket(dynamic packet) {
|
void _handleWebSocketPacket(dynamic packet) {
|
||||||
if (packet.type.startsWith('task.')) {
|
if (packet.type.startsWith('task.') || packet.type == 'upload.completed') {
|
||||||
final data = packet.data;
|
final data = packet.data;
|
||||||
if (data == null) return;
|
if (data == null && packet.type != 'upload.completed') return;
|
||||||
|
|
||||||
// Debug logging
|
// Debug logging
|
||||||
talker.info(
|
talker.info(
|
||||||
'[UploadTasks] Received WebSocket packet: ${packet.type}, data: $data',
|
'[UploadTasks] Received WebSocket packet: ${packet.type}, data: $data',
|
||||||
);
|
);
|
||||||
|
|
||||||
final taskId = data['task_id'] as String?;
|
final taskId = data != null ? (data['task_id'] as String?) : null;
|
||||||
if (taskId == null) return;
|
if (taskId == null && packet.type != 'upload.completed') return;
|
||||||
|
|
||||||
switch (packet.type) {
|
switch (packet.type) {
|
||||||
case 'task.created':
|
case 'task.created':
|
||||||
_handleTaskCreated(taskId, data);
|
_handleTaskCreated(taskId!, data);
|
||||||
break;
|
break;
|
||||||
case 'task.progress':
|
case 'task.progress':
|
||||||
_handleProgressUpdate(taskId, data);
|
_handleProgressUpdate(taskId!, data);
|
||||||
break;
|
break;
|
||||||
case 'task.completed':
|
case 'task.completed':
|
||||||
_handleUploadCompleted(taskId, data);
|
_handleUploadCompleted(taskId!, data);
|
||||||
|
break;
|
||||||
|
case 'upload.completed':
|
||||||
|
// For upload.completed, we need to find the taskId differently
|
||||||
|
// Since data is null, we can't get task_id from data
|
||||||
|
// We'll need to mark all in-progress uploads as completed
|
||||||
|
// For now, assume we need to handle it per task, but since no task_id,
|
||||||
|
// perhaps it's a broadcast or we need to modify the logic
|
||||||
|
// Actually, looking at the logs, upload.completed has data: null, but maybe in real scenario it has task_id?
|
||||||
|
// For now, let's assume it needs task_id, and modify accordingly
|
||||||
|
// But since the original code expects data, perhaps the server sends data with task_id
|
||||||
|
// Wait, in the logs: "upload.completed null" - the null is data, but perhaps in code it's null
|
||||||
|
// To be safe, let's modify to handle upload.completed even with null data, but we need task_id
|
||||||
|
// Perhaps search for in-progress tasks and complete them
|
||||||
|
// But that's risky. Let's see the log again: the previous task.progress had task_id: YvvfVbaWSxj5vUnFnzJDu
|
||||||
|
// So probably upload.completed should have the same task_id
|
||||||
|
// Perhaps the server sends it with data containing task_id
|
||||||
|
// The log says "upload.completed null" meaning data is null
|
||||||
|
// But maybe it's a logging issue. To fix, let's assume data has task_id for upload.completed
|
||||||
|
// If not, we can modify _handleUploadCompleted to accept null data and find the task
|
||||||
|
if (data != null && data['task_id'] != null) {
|
||||||
|
_handleUploadCompleted(data['task_id'], data);
|
||||||
|
} else {
|
||||||
|
// If no data, perhaps complete the most recent in-progress task
|
||||||
|
final inProgressTasks = state.where((task) => task.status == DriveTaskStatus.inProgress).toList();
|
||||||
|
if (inProgressTasks.isNotEmpty) {
|
||||||
|
final task = inProgressTasks.last; // Assume the last one
|
||||||
|
_handleUploadCompleted(task.taskId, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'task.failed':
|
case 'task.failed':
|
||||||
_handleUploadFailed(taskId, data);
|
_handleUploadFailed(taskId!, data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,6 +285,21 @@ class UploadTasksNotifier extends Notifier<List<DriveTask>> {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateUploadProgress(String taskId, int uploadedBytes, int uploadedChunks) {
|
||||||
|
state =
|
||||||
|
state.map((task) {
|
||||||
|
if (task.taskId == taskId) {
|
||||||
|
return task.copyWith(
|
||||||
|
uploadedBytes: uploadedBytes,
|
||||||
|
uploadedChunks: uploadedChunks,
|
||||||
|
status: DriveTaskStatus.inProgress,
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
void updateDownloadProgress(
|
void updateDownloadProgress(
|
||||||
String taskId,
|
String taskId,
|
||||||
int downloadedBytes,
|
int downloadedBytes,
|
||||||
@@ -470,6 +514,7 @@ class EnhancedFileUploader extends FileUploader {
|
|||||||
|
|
||||||
// Step 2: Upload chunks
|
// Step 2: Upload chunks
|
||||||
int bytesUploaded = 0;
|
int bytesUploaded = 0;
|
||||||
|
int chunksUploaded = 0;
|
||||||
if (fileData is XFile) {
|
if (fileData is XFile) {
|
||||||
// Use stream for XFile
|
// Use stream for XFile
|
||||||
final subscription = fileData.openRead().listen(null);
|
final subscription = fileData.openRead().listen(null);
|
||||||
@@ -494,6 +539,11 @@ class EnhancedFileUploader extends FileUploader {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
bytesUploaded += chunkData.length;
|
bytesUploaded += chunkData.length;
|
||||||
|
chunksUploaded += 1;
|
||||||
|
// Update upload progress in UI
|
||||||
|
ref
|
||||||
|
.read(uploadTasksProvider.notifier)
|
||||||
|
.updateUploadProgress(taskId, bytesUploaded, chunksUploaded);
|
||||||
}
|
}
|
||||||
subscription.cancel();
|
subscription.cancel();
|
||||||
} else if (fileData is Uint8List) {
|
} else if (fileData is Uint8List) {
|
||||||
@@ -521,6 +571,11 @@ class EnhancedFileUploader extends FileUploader {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
bytesUploaded += chunks[i].length;
|
bytesUploaded += chunks[i].length;
|
||||||
|
chunksUploaded += 1;
|
||||||
|
// Update upload progress in UI
|
||||||
|
ref
|
||||||
|
.read(uploadTasksProvider.notifier)
|
||||||
|
.updateUploadProgress(taskId, bytesUploaded, chunksUploaded);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw ArgumentError('Invalid fileData type');
|
throw ArgumentError('Invalid fileData type');
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ part of 'event_calendar.dart';
|
|||||||
/// This can be used anywhere in the app where calendar data is needed
|
/// This can be used anywhere in the app where calendar data is needed
|
||||||
|
|
||||||
@ProviderFor(eventCalendar)
|
@ProviderFor(eventCalendar)
|
||||||
const eventCalendarProvider = EventCalendarFamily._();
|
final eventCalendarProvider = EventCalendarFamily._();
|
||||||
|
|
||||||
/// Provider for fetching event calendar data
|
/// Provider for fetching event calendar data
|
||||||
/// This can be used anywhere in the app where calendar data is needed
|
/// This can be used anywhere in the app where calendar data is needed
|
||||||
@@ -29,7 +29,7 @@ final class EventCalendarProvider
|
|||||||
$FutureProvider<List<SnEventCalendarEntry>> {
|
$FutureProvider<List<SnEventCalendarEntry>> {
|
||||||
/// Provider for fetching event calendar data
|
/// Provider for fetching event calendar data
|
||||||
/// This can be used anywhere in the app where calendar data is needed
|
/// This can be used anywhere in the app where calendar data is needed
|
||||||
const EventCalendarProvider._({
|
EventCalendarProvider._({
|
||||||
required EventCalendarFamily super.from,
|
required EventCalendarFamily super.from,
|
||||||
required EventCalendarQuery super.argument,
|
required EventCalendarQuery super.argument,
|
||||||
}) : super(
|
}) : super(
|
||||||
@@ -84,7 +84,7 @@ final class EventCalendarFamily extends $Family
|
|||||||
FutureOr<List<SnEventCalendarEntry>>,
|
FutureOr<List<SnEventCalendarEntry>>,
|
||||||
EventCalendarQuery
|
EventCalendarQuery
|
||||||
> {
|
> {
|
||||||
const EventCalendarFamily._()
|
EventCalendarFamily._()
|
||||||
: super(
|
: super(
|
||||||
retry: null,
|
retry: null,
|
||||||
name: r'eventCalendarProvider',
|
name: r'eventCalendarProvider',
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user