Compare commits
	
		
			155 Commits
		
	
	
		
			f478ea8b84
			...
			3.2.0+131
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6f9d51673b | |||
| f8c6887769 | |||
| cd2a507b7f | |||
| 3cafce00a2 | |||
| 837f3fbe98 | |||
| ca7cc5d7ee | |||
| ef2c14daa2 | |||
| 3a17837cc6 | |||
| 2617a64acf | |||
| afe1e12a3b | |||
| be80f5ff85 | |||
| 3281d69eba | |||
| 77b6ce9937 | |||
| 39275f61b5 | |||
| 72193ba8f3 | |||
| 98dd9b6617 | |||
| a22b94a263 | |||
| 9c75eafdb3 | |||
| 28fda3d0c7 | |||
| 187c2ea43e | |||
| ae7d967461 | |||
| 1ce71f1fa1 | |||
| 9b68808c77 | |||
|  | 99b7bf8199 | ||
|  | eb9bb73c31 | ||
|  | a8c3830d67 | ||
|  | 07a5a19141 | ||
| ecc100ac45 | |||
| 573b76d3ff | |||
| f7dad5e419 | |||
| 9f2f1c0848 | |||
| 580d9fd979 | |||
| 3b375abc09 | |||
| c527b5e67c | |||
| e9f09bbe54 | |||
| 3aece9316c | |||
| a61c889c6c | |||
| 0dd3221a56 | |||
| 66918521f8 | |||
| bb1846e462 | |||
| a976a6eaf4 | |||
| 4252f66fd3 | |||
| f2d780b48f | |||
| 300541f9bb | |||
| 43787bb813 | |||
| 3417c51a3b | |||
| f98e603e82 | |||
| c9b71701c8 | |||
| 28e98488f1 | |||
| b4d476613e | |||
| b48a1aac44 | |||
| 596d212593 | |||
| 54f290327e | |||
| 16f248ceab | |||
| 856d811187 | |||
| d07b194c04 | |||
| 2554b58be6 | |||
| a627b5838e | |||
| c479a9f381 | |||
| 02057e663b | |||
| 6501594100 | |||
| c6599edc3d | |||
| 709a0620b6 | |||
| f9b2a96c7c | |||
| 4dca6189cb | |||
| c7f5b63fe5 | |||
| 96c2f45c85 | |||
| 06f04eb3a5 | |||
| 8af97e43b4 | |||
| d1e8234b93 | |||
| a03d6015a6 | |||
| 246ac52d0a | |||
| abf395ff9a | |||
| 4fdc8eb1d0 | |||
| d7dcde898c | |||
| f85484d3ed | |||
| 5060bd30c9 | |||
| 3959f2260b | |||
| 6f4f1216ad | |||
| f401ffbf81 | |||
| 0251697951 | |||
| 178c12b893 | |||
| 4beda9200e | |||
| 7dfe411053 | |||
| 1232318a5d | |||
|  | 56f41b6c0e | ||
|  | 3ea717d25a | ||
| 1fe4889460 | |||
| cdf2722268 | |||
| a127b5bace | |||
| b2097cf044 | |||
| 701f29748d | |||
| 9e40ed4600 | |||
| c90e6fe661 | |||
| 569483300d | |||
| bab602d98b | |||
| b4f2bb803a | |||
| 03bfed6f46 | |||
| f98e5a0aec | |||
| 3d473e2fec | |||
| 0b6efa373a | |||
| 9b60e96cde | |||
| 81cd9b2082 | |||
| 923d5d7514 | |||
| 7169aff841 | |||
| fac3efb50c | |||
| e809aadaea | |||
| f33b569221 | |||
| e5f2e2d146 | |||
| 11368d064f | |||
| 246b163aec | |||
| 10e0d2fe5f | |||
| 99e10cb612 | |||
| 1db6941431 | |||
| 8370da4fe3 | |||
| 2bdf7029e9 | |||
| 86682a3a9a | |||
| c3925e81b5 | |||
| 6f1f488490 | |||
| 31b2de2e46 | |||
| 412dcfa62a | |||
| ffdc7e81ae | |||
| 1d3357803d | |||
| 6c48aa2356 | |||
| 466e354679 | |||
| 5d4b896f70 | |||
| a04dffdfe8 | |||
| ff871943cf | |||
| 1a892ab227 | |||
| af1b303211 | |||
| 6fd702eba8 | |||
| d220d43cd2 | |||
| 6892afb974 | |||
| 007b46b080 | |||
| 67d130dc34 | |||
| 7e923c77fe | |||
| a593b52812 | |||
|  | 520dc80303 | ||
| 001897bbcd | |||
|  | bab29c23e3 | ||
| 76b39f2df3 | |||
| 509b3e145b | |||
| 2b80ebc2d0 | |||
| 0ab908dd2a | |||
| 6007467e7a | |||
| 3745157c42 | |||
| 94481ec7bd | |||
| fbfe8cbdee | |||
| fbbab0a981 | |||
| ae2fb3b303 | |||
| 3d7a4666ed | |||
| 5d3e0fb800 | |||
| 85ff52a661 | |||
| da7fd64a43 | |||
| 3902633217 | 
							
								
								
									
										9
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -41,6 +41,15 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           name: build-output-windows |           name: build-output-windows | ||||||
|           path: build/windows/x64/runner/Release |           path: build/windows/x64/runner/Release | ||||||
|  |       - name: Compile Installer | ||||||
|  |         uses: Minionguyjpro/Inno-Setup-Action@v1.2.2 | ||||||
|  |         with: | ||||||
|  |           path: setup.iss | ||||||
|  |       - name: Archive installer artifacts | ||||||
|  |         uses: actions/upload-artifact@v4 | ||||||
|  |         with: | ||||||
|  |           name: build-output-windows-installer | ||||||
|  |           path: Installer/windows-x86_64-setup.exe | ||||||
|   build-linux: |   build-linux: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|   | |||||||
| @@ -62,4 +62,3 @@ If you want to build the release version, use the flutter build command. Learn m | |||||||
| ```bash | ```bash | ||||||
| flutter build <platform> | flutter build <platform> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 70 KiB | 
							
								
								
									
										41
									
								
								android/app/src/main/res/drawable/ic_notification.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								android/app/src/main/res/drawable/ic_notification.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     android:width="192dp" | ||||||
|  |     android:height="192dp" | ||||||
|  |     android:viewportWidth="192" | ||||||
|  |     android:viewportHeight="192"> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M54,147h86" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="12" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M57,111s-2,-4.5 -2,-10m22,22s-4,7 -11,4m9,-22s-2,-4.5 -2,-10" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="10" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M54,147a32,32 0,0 1,-12 -61.67A39,39 0,0 1,81 46m59,101a30,30 0,0 0,29.93 -28" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="12" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M132,75m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="8" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M112.5,41.22C100.84,47.96 93,60.56 93,75c0,6.38 1.53,12.39 4.24,17.71m69.51,-35.42A38.84,38.84 0,0 1,171 75c0,14.43 -7.84,27.03 -19.49,33.78m-0.79,-43.32A20.9,20.9 0,0 1,153 75c0,7.77 -4.22,14.56 -10.49,18.19m-21,-36.38C115.22,60.44 111,67.23 111,75a20.9,20.9 0,0 0,2.28 9.53" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="10" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  | </vector> | ||||||
| @@ -195,6 +195,7 @@ | |||||||
|   "checkInResultLevel2": "A Normal Day", |   "checkInResultLevel2": "A Normal Day", | ||||||
|   "checkInResultLevel3": "Good Luck", |   "checkInResultLevel3": "Good Luck", | ||||||
|   "checkInResultLevel4": "Best Luck", |   "checkInResultLevel4": "Best Luck", | ||||||
|  |   "checkInResultLevel5": "Happy Birthday 🥳", | ||||||
|   "checkInActivityTitle": "{} checked in on {} and got a {}", |   "checkInActivityTitle": "{} checked in on {} and got a {}", | ||||||
|   "eventCalander": "Event Calander", |   "eventCalander": "Event Calander", | ||||||
|   "eventCalanderEmpty": "No events on that day.", |   "eventCalanderEmpty": "No events on that day.", | ||||||
| @@ -228,6 +229,8 @@ | |||||||
|   "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.", | ||||||
|  |   "region": "Region", | ||||||
|  |   "accountRegionHint": "This region will be used for content delivery and localization.", | ||||||
|   "settingsDisplayLanguage": "Display Language", |   "settingsDisplayLanguage": "Display Language", | ||||||
|   "languageFollowSystem": "Follow System", |   "languageFollowSystem": "Follow System", | ||||||
|   "postsCreatedCount": "Posts", |   "postsCreatedCount": "Posts", | ||||||
| @@ -334,9 +337,11 @@ | |||||||
|   "walletCreate": "Create a Wallet", |   "walletCreate": "Create a Wallet", | ||||||
|   "settingsServerUrl": "Server URL", |   "settingsServerUrl": "Server URL", | ||||||
|   "settingsApplied": "The settings has been applied.", |   "settingsApplied": "The settings has been applied.", | ||||||
|  |   "settingsCustomFontsHelper": "Use comma to seprate.", | ||||||
|   "notifications": "Notifications", |   "notifications": "Notifications", | ||||||
|   "posts": "Posts", |   "posts": "Posts", | ||||||
|   "settingsBackgroundImage": "Background Image", |   "settingsBackgroundImage": "Background Image", | ||||||
|  |   "settingsBackgroundImageEnable": "Show Background Image", | ||||||
|   "settingsBackgroundImageClear": "Clear Background Image", |   "settingsBackgroundImageClear": "Clear Background Image", | ||||||
|   "settingsBackgroundGenerateColor": "Generate color scheme from Bacground Image", |   "settingsBackgroundGenerateColor": "Generate color scheme from Bacground Image", | ||||||
|   "messageNone": "No content to display", |   "messageNone": "No content to display", | ||||||
| @@ -347,6 +352,8 @@ | |||||||
|   "chatBreakNone": "None", |   "chatBreakNone": "None", | ||||||
|   "settingsRealmCompactView": "Compact Realm View", |   "settingsRealmCompactView": "Compact Realm View", | ||||||
|   "settingsMixedFeed": "Mixed Feed", |   "settingsMixedFeed": "Mixed Feed", | ||||||
|  |   "settingsDataSavingMode": "Data Saving Mode", | ||||||
|  |   "dataSavingHint": "Data Saving Mode", | ||||||
|   "settingsAutoTranslate": "Auto Translate", |   "settingsAutoTranslate": "Auto Translate", | ||||||
|   "settingsHideBottomNav": "Hide Bottom Navigation", |   "settingsHideBottomNav": "Hide Bottom Navigation", | ||||||
|   "settingsSoundEffects": "Sound Effects", |   "settingsSoundEffects": "Sound Effects", | ||||||
| @@ -385,6 +392,7 @@ | |||||||
|   "postSettings": "Settings", |   "postSettings": "Settings", | ||||||
|   "postPublisherUnselected": "Publisher Unspecified", |   "postPublisherUnselected": "Publisher Unspecified", | ||||||
|   "postType": "Post Type", |   "postType": "Post Type", | ||||||
|  |   "postTypePost": "Post", | ||||||
|   "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", | ||||||
|   "postVisibilityPublic": "Public", |   "postVisibilityPublic": "Public", | ||||||
| @@ -632,8 +640,9 @@ | |||||||
|   "chatJoin": "Join the Chat", |   "chatJoin": "Join the Chat", | ||||||
|   "realmJoin": "Join the Realm", |   "realmJoin": "Join the Realm", | ||||||
|   "realmJoinSuccess": "Successfully joined the realm.", |   "realmJoinSuccess": "Successfully joined the realm.", | ||||||
|   "discoverRealms": "Discover realms", |   "discoverRealms": "Realms", | ||||||
|   "discoverPublishers": "Discover publishers", |   "discoverPublishers": "Publishers", | ||||||
|  |   "discoverShuffledPost": "Random Posts", | ||||||
|   "search": "Search", |   "search": "Search", | ||||||
|   "publisherMembers": "Collaborators", |   "publisherMembers": "Collaborators", | ||||||
|   "developerHub": "Developer Hub", |   "developerHub": "Developer Hub", | ||||||
| @@ -642,6 +651,18 @@ | |||||||
|   "enrollDeveloperHint": "Enroll one of your publishers to become a developer.", |   "enrollDeveloperHint": "Enroll one of your publishers to become a developer.", | ||||||
|   "noPublishersToEnroll": "You don't have any publishers that can be enrolled as a developer.", |   "noPublishersToEnroll": "You don't have any publishers that can be enrolled as a developer.", | ||||||
|   "totalCustomApps": "Total Custom Apps", |   "totalCustomApps": "Total Custom Apps", | ||||||
|  |   "projects": "Projects", | ||||||
|  |   "noProjects": "No projects found.", | ||||||
|  |   "deleteProject": "Delete Project", | ||||||
|  |   "deleteProjectHint": "Are you sure you want to delete this project? This action cannot be undone.", | ||||||
|  |   "createProject": "Create Project", | ||||||
|  |   "editProject": "Edit Project", | ||||||
|  |   "projectDetails": "Project Details", | ||||||
|  |   "createBot": "Create Bot", | ||||||
|  |   "bots": "Bots", | ||||||
|  |   "noBots": "No bots yet.", | ||||||
|  |   "deleteBotHint": "Are you sure you want to delete this bot? This action cannot be undone.", | ||||||
|  |   "deleteBot": "Delete Bot", | ||||||
|   "customApps": "Custom Apps", |   "customApps": "Custom Apps", | ||||||
|   "noCustomApps": "No custom apps yet.", |   "noCustomApps": "No custom apps yet.", | ||||||
|   "createCustomApp": "Create Custom App", |   "createCustomApp": "Create Custom App", | ||||||
| @@ -679,7 +700,7 @@ | |||||||
|   "publisherFeatureDevelopDescription": "Unlock development abilities for your publisher, including custom apps, API keys, and more.", |   "publisherFeatureDevelopDescription": "Unlock development abilities for your publisher, including custom apps, API keys, and more.", | ||||||
|   "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", | ||||||
|   "discoverWebArticles": "Articles from external sites", |   "discoverWebArticles": "Web Feed Articles", | ||||||
|   "webArticlesStand": "Article Stand", |   "webArticlesStand": "Article Stand", | ||||||
|   "about": "About", |   "about": "About", | ||||||
|   "membershipCancel": "Cancel Membership", |   "membershipCancel": "Cancel Membership", | ||||||
| @@ -836,5 +857,125 @@ | |||||||
|   "pollAddOption": "Add option", |   "pollAddOption": "Add option", | ||||||
|   "pollOptionLabel": "Option label", |   "pollOptionLabel": "Option label", | ||||||
|   "pollLongTextAnswerPreview": "Long text answer (preview)", |   "pollLongTextAnswerPreview": "Long text answer (preview)", | ||||||
|   "pollShortTextAnswerPreview": "Short text answer (preview)" |   "pollShortTextAnswerPreview": "Short text answer (preview)", | ||||||
|  |   "messageJumpNotLoaded": "The referenced message was not loaded, unable to jump to it.", | ||||||
|  |   "postUnlinkRealm": "No linked realm", | ||||||
|  |   "postSlug": "Slug", | ||||||
|  |   "postSlugHint": "The slug can be used to access your post via URL in the webpage, it should be publisher-wide unique.", | ||||||
|  |   "attachmentOnDevice": "On-device", | ||||||
|  |   "attachmentOnCloud": "On-cloud", | ||||||
|  |   "attachments": "Attachments", | ||||||
|  |   "publisherCollabInvitation": "Collabration invitations", | ||||||
|  |   "publisherCollabInvitationCount": { | ||||||
|  |     "zero": "No invitation", | ||||||
|  |     "one": "{} available invitation", | ||||||
|  |     "other": "{} available invitations" | ||||||
|  |   }, | ||||||
|  |   "failedToLoadUserInfo": "Failed to load user info", | ||||||
|  |   "failedToLoadUserInfoNetwork": "It seems be network issue, you can tap the button below to try again.", | ||||||
|  |   "failedToLoadUserInfoUnauthorized": "It seems your session has been logged out or not available anymore, you can still try agian to fetch the user info if you want.", | ||||||
|  |   "okay": "Okay", | ||||||
|  |   "postDetail": "Post Detail", | ||||||
|  |   "postCount": { | ||||||
|  |     "zero": "No posts", | ||||||
|  |     "one": "{} post", | ||||||
|  |     "other": "{} posts" | ||||||
|  |   }, | ||||||
|  |   "mimeType": "MIME Type", | ||||||
|  |   "fileSize": "File Size", | ||||||
|  |   "fileHash": "File Hash", | ||||||
|  |   "exifData": "EXIF Data", | ||||||
|  |   "postShuffle": "Shuffle Posts", | ||||||
|  |   "leveling": "Leveling", | ||||||
|  |   "levelingHistory": "Leveling History", | ||||||
|  |   "stellarProgram": "Stellar Program", | ||||||
|  |   "socialCredits": "Social Credits", | ||||||
|  |   "credits": "Credits", | ||||||
|  |   "creditsStatus": "Credits Status", | ||||||
|  |   "socialCreditsDescription": "Social Credit is a way for Solar Network to evaluate users. It is calculated based on their behavior and interactions. With a base score of 100, higher scores indicate a user's credibility within the community. Scores change over time to reflect a user's recent behavior. Users with higher credit ratings enjoy more benefits, while users with lower credit ratings may have some functionality restricted.", | ||||||
|  |   "socialCreditsLevelPoor": "Poor", | ||||||
|  |   "socialCreditsLevelNormal": "Normal", | ||||||
|  |   "socialCreditsLevelGood": "Good", | ||||||
|  |   "socialCreditsLevelExcellent": "Excellent", | ||||||
|  |   "orderByPopularity": "Sort by popularity", | ||||||
|  |   "orderByReleaseDate": "Sort by release date", | ||||||
|  |   "editBot": "Edit Bot", | ||||||
|  |   "botAutomatedBy": "Automated by {}", | ||||||
|  |   "botDetails": "Bot Details", | ||||||
|  |   "overview": "Overview", | ||||||
|  |   "keys": "Keys", | ||||||
|  |   "botNotFound": "Bot not found.", | ||||||
|  |   "newBotKey": "New Bot Key", | ||||||
|  |   "newBotKeyHint": "Enter a name for your new key. The key will be shown only once.", | ||||||
|  |   "revokeBotKey": "Revoke Bot Key", | ||||||
|  |   "revokeBotKeyHint": "Are you sure you want to revoke this key? This action cannot be undone and any application using this key will stop working.", | ||||||
|  |   "noBotKeys": "No bot keys yet.", | ||||||
|  |   "revoke": "Revoke", | ||||||
|  |   "keyName": "Key Name", | ||||||
|  |   "newKeyGenerated": "New Key Generated", | ||||||
|  |   "copyKeyHint": "Please copy this key and store it somewhere safe. You will not be able to see it again.", | ||||||
|  |   "rotateKey": "Rotate Key", | ||||||
|  |   "rotateBotKey": "Rotate Bot Key", | ||||||
|  |   "rotateBotKeyHint": "Are you sure you want to rotate this key? The old key will become invalid immediately. This action cannot be undone.", | ||||||
|  |   "webFeedArticleCount": { | ||||||
|  |     "zero": "No articles", | ||||||
|  |     "one": "{} article", | ||||||
|  |     "other": "{} articles" | ||||||
|  |   }, | ||||||
|  |   "webFeedSubscribed": "The feed has been subscribed", | ||||||
|  |   "webFeedUnsubscribed": "The feed has been unsubscribed", | ||||||
|  |   "appDetails": "App Details", | ||||||
|  |   "secrets": "Secrets", | ||||||
|  |   "appNotFound": "App not found.", | ||||||
|  |   "secretCopied": "Secret copied to clipboard.", | ||||||
|  |   "deleteSecret": "Delete Secret", | ||||||
|  |   "deleteSecretHint": "Are you sure you want to delete this secret? This action cannot be undone.", | ||||||
|  |   "generateSecret": "Generate New Secret", | ||||||
|  |   "createdAt": "Created at {}", | ||||||
|  |   "newSecretGenerated": "New Secret Generated", | ||||||
|  |   "copySecretHint": "Please copy this secret and store it somewhere safe. You will not be able to see it again.", | ||||||
|  |   "expiresIn": "Expires In (seconds)", | ||||||
|  |   "isOidc": "OIDC Compliant", | ||||||
|  |   "pinPost": "Pin Post", | ||||||
|  |   "unpinPost": "Unpin Post", | ||||||
|  |   "pinnedPost": "Pinned", | ||||||
|  |   "publisherPage": "Publisher Page", | ||||||
|  |   "realmPage": "Realm Page", | ||||||
|  |   "replyPage": "Reply Page", | ||||||
|  |   "pinPostPublisherHint": "Pin this post to your publisher page", | ||||||
|  |   "pinPostRealmHint": "Pin this post to the realm page", | ||||||
|  |   "pinPostRealmDisabledHint": "This post doesn't belong to any realm", | ||||||
|  |   "pinPostReplyHint": "Pin this post to the reply page", | ||||||
|  |   "pinPostReplyDisabledHint": "This post is not a reply", | ||||||
|  |   "pin": "Pin", | ||||||
|  |   "unpinPostHint": "Are you sure you want to unpin this post?", | ||||||
|  |   "all": "All", | ||||||
|  |   "statusPresent": "Present", | ||||||
|  |   "accountAutomated": "Automated", | ||||||
|  |   "chatBreakClearButton": "Clear", | ||||||
|  |   "chatBreak5m": "5m", | ||||||
|  |   "chatBreak10m": "10m", | ||||||
|  |   "chatBreak15m": "15m", | ||||||
|  |   "chatBreak30m": "30m", | ||||||
|  |   "chatBreakCustomMinutes": "Custom (minutes)", | ||||||
|  |   "errorGeneric": "Error: {}", | ||||||
|  |   "searchMessages": "Search Messages", | ||||||
|  |   "messagesCount": "{} messages", | ||||||
|  |   "dotSeparator": "·", | ||||||
|  |   "roleValidationHint": "Role must be between 0 and 100", | ||||||
|  |   "searchMessagesHint": "Search messages...", | ||||||
|  |   "searchLinks": "Links", | ||||||
|  |   "searchAttachments": "Attachments", | ||||||
|  |   "noMessagesFound": "No messages found", | ||||||
|  |   "openInBrowser": "Open in Browser", | ||||||
|  |   "highlightPost": "Highlight Post", | ||||||
|  |   "filters": "Filters", | ||||||
|  |   "apply": "Apply", | ||||||
|  |   "pubName": "Pub Name", | ||||||
|  |   "realm": "Realm", | ||||||
|  |   "shuffle": "Shuffle", | ||||||
|  |   "pinned": "Pinned", | ||||||
|  |   "noResultsFound": "No results found", | ||||||
|  |   "toggleFilters": "Toggle filters", | ||||||
|  |   "notableDayNext": "{} is in" | ||||||
| } | } | ||||||
| @@ -158,11 +158,12 @@ | |||||||
|   "checkIn": "签到", |   "checkIn": "签到", | ||||||
|   "checkInNone": "尚未签到", |   "checkInNone": "尚未签到", | ||||||
|   "checkInNoneHint": "通过签到获取您的财富提示和每日奖励。", |   "checkInNoneHint": "通过签到获取您的财富提示和每日奖励。", | ||||||
|     "checkInResultLevel0": "最差运气", |   "checkInResultLevel0": "大凶", | ||||||
|     "checkInResultLevel1": "坏运气", |   "checkInResultLevel1": "凶", | ||||||
|     "checkInResultLevel2": "一个普通的日常", |   "checkInResultLevel2": "中平", | ||||||
|     "checkInResultLevel3": "好运", |   "checkInResultLevel3": "吉", | ||||||
|     "checkInResultLevel4": "最佳运气", |   "checkInResultLevel4": "大吉", | ||||||
|  |   "checkInResultLevel5": "生日快乐 🥳", | ||||||
|   "checkInActivityTitle": "{} 在 {} 签到并获得了 {}", |   "checkInActivityTitle": "{} 在 {} 签到并获得了 {}", | ||||||
|   "eventCalander": "活动日历", |   "eventCalander": "活动日历", | ||||||
|   "eventCalanderEmpty": "该日无活动。", |   "eventCalanderEmpty": "该日无活动。", | ||||||
| @@ -300,9 +301,11 @@ | |||||||
|   "walletCreate": "创建钱包", |   "walletCreate": "创建钱包", | ||||||
|   "settingsServerUrl": "服务器 URL", |   "settingsServerUrl": "服务器 URL", | ||||||
|   "settingsApplied": "设置已应用。", |   "settingsApplied": "设置已应用。", | ||||||
|  |   "settingsCustomFontsHelper": "用逗号分隔。", | ||||||
|   "notifications": "通知", |   "notifications": "通知", | ||||||
|   "posts": "帖子", |   "posts": "帖子", | ||||||
|   "settingsBackgroundImage": "背景图片", |   "settingsBackgroundImage": "背景图片", | ||||||
|  |   "settingsBackgroundImageEnable": "显示背景图片", | ||||||
|   "settingsBackgroundImageClear": "清除背景图片", |   "settingsBackgroundImageClear": "清除背景图片", | ||||||
|   "settingsBackgroundGenerateColor": "从背景图像生成主题色", |   "settingsBackgroundGenerateColor": "从背景图像生成主题色", | ||||||
|   "messageNone": "没有内容可显示", |   "messageNone": "没有内容可显示", | ||||||
| @@ -313,6 +316,8 @@ | |||||||
|   "chatBreakNone": "无", |   "chatBreakNone": "无", | ||||||
|   "settingsRealmCompactView": "紧凑领域视图", |   "settingsRealmCompactView": "紧凑领域视图", | ||||||
|   "settingsMixedFeed": "混合动态", |   "settingsMixedFeed": "混合动态", | ||||||
|  |   "settingsDataSavingMode": "流量节省模式", | ||||||
|  |   "dataSavingHint": "流量节省模式", | ||||||
|   "settingsAutoTranslate": "自动翻译", |   "settingsAutoTranslate": "自动翻译", | ||||||
|   "settingsHideBottomNav": "隐藏底部导航", |   "settingsHideBottomNav": "隐藏底部导航", | ||||||
|   "settingsSoundEffects": "音效", |   "settingsSoundEffects": "音效", | ||||||
| @@ -344,7 +349,7 @@ | |||||||
|   "accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。", |   "accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。", | ||||||
|   "unauthorized": "未授权", |   "unauthorized": "未授权", | ||||||
|   "unauthorizedHint": "您未登录或会话已过期,请重新登录。", |   "unauthorizedHint": "您未登录或会话已过期,请重新登录。", | ||||||
|     "publisherBelongsTo": "属于", |   "publisherBelongsTo": "属于 {}", | ||||||
|   "postContent": "内容", |   "postContent": "内容", | ||||||
|   "postSettings": "设置", |   "postSettings": "设置", | ||||||
|   "postPublisherUnselected": "未指定发布者", |   "postPublisherUnselected": "未指定发布者", | ||||||
| @@ -811,5 +816,53 @@ | |||||||
|   "filesListAdditional": { |   "filesListAdditional": { | ||||||
|     "one": "+{} 个文件被折叠", |     "one": "+{} 个文件被折叠", | ||||||
|     "other": "+{} 个文件被折叠" |     "other": "+{} 个文件被折叠" | ||||||
|     } |   }, | ||||||
|  |   "messageJumpNotLoaded": "引用的消息没有被加载,无法跳转。", | ||||||
|  |   "postUnlinkRealm": "不关联领域", | ||||||
|  |   "postSlug": "别名", | ||||||
|  |   "postSlugHint": "这个别名可以用于在网页通过 URL 浏览到你的帖子,它应该在同一发布者中是唯一。", | ||||||
|  |   "attachmentOnDevice": "离线", | ||||||
|  |   "attachmentOnCloud": "在线", | ||||||
|  |   "publisherCollabInvitation": "协作邀请", | ||||||
|  |   "publisherCollabInvitationCount": { | ||||||
|  |     "zero": "无邀请", | ||||||
|  |     "one": "{} 个可用邀请", | ||||||
|  |     "other": "{} 个可用邀请" | ||||||
|  |   }, | ||||||
|  |   "failedToLoadUserInfo": "加载用户信息失败", | ||||||
|  |   "failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试", | ||||||
|  |   "failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。", | ||||||
|  |   "okay": "了解", | ||||||
|  |   "postDetail": "帖子详情", | ||||||
|  |   "mimeType": "类型", | ||||||
|  |   "fileSize": "大小", | ||||||
|  |   "fileHash": "哈希", | ||||||
|  |   "exifData": "EXIF 数据", | ||||||
|  |   "leveling": "等级", | ||||||
|  |   "levelingHistory": "经验记录", | ||||||
|  |   "stellarProgram": "恒星计划", | ||||||
|  |   "socialCredits": "社会信用点", | ||||||
|  |   "credits": "信用", | ||||||
|  |   "socialCreditsDescription": "社会信用是 Solar Network 评价用户的一种方式。它基于用户的行为和互动来计算。以 100 分为基准,分数越高表示用户在社区中的信誉越好。分数会随着时间的推移而变化,反映用户的最新行为。信用等级高的用户可以享受到更多的福利,反之的用户部份功能可能受到限制。", | ||||||
|  |   "socialCreditsLevelPoor": "糟糕", | ||||||
|  |   "socialCreditsLevelNormal": "正常", | ||||||
|  |   "socialCreditsLevelGood": "良好", | ||||||
|  |   "socialCreditsLevelExcellent": "优秀", | ||||||
|  |   "appDetails": "应用详情", | ||||||
|  |   "secrets": "密钥", | ||||||
|  |   "appNotFound": "应用未找到。", | ||||||
|  |   "secretCopied": "密钥已复制到剪贴板。", | ||||||
|  |   "deleteSecret": "删除密钥", | ||||||
|  |   "deleteSecretHint": "您确定要删除此密钥吗?此操作无法撤销。", | ||||||
|  |   "generateSecret": "生成新密钥", | ||||||
|  |   "createdAt": "创建于 {}", | ||||||
|  |   "newSecretGenerated": "已生成新密钥", | ||||||
|  |   "copySecretHint": "请复制此密钥并将其存放在安全的地方。您将无法再次看到它。", | ||||||
|  |   "expiresIn": "过期时间(秒)", | ||||||
|  |   "isOidc": "OIDC 兼容", | ||||||
|  |   "statusPresent": "至今", | ||||||
|  |   "accountAutomated": "机器人", | ||||||
|  |   "openInBrowser": "在浏览器中打开", | ||||||
|  |   "highlightPost": "精选帖子", | ||||||
|  |   "notableDayNext": "距离 {} 还有" | ||||||
| } | } | ||||||
| @@ -303,6 +303,7 @@ | |||||||
|     "notifications": "通知", |     "notifications": "通知", | ||||||
|     "posts": "帖子", |     "posts": "帖子", | ||||||
|     "settingsBackgroundImage": "背景圖片", |     "settingsBackgroundImage": "背景圖片", | ||||||
|  |   "settingsBackgroundImageEnable": "顯示背景圖片", | ||||||
|   "settingsBackgroundImageClear": "清除背景圖片", |   "settingsBackgroundImageClear": "清除背景圖片", | ||||||
|     "settingsBackgroundGenerateColor": "從背景圖像生成主題色", |     "settingsBackgroundGenerateColor": "從背景圖像生成主題色", | ||||||
|     "messageNone": "沒有內容可顯示", |     "messageNone": "沒有內容可顯示", | ||||||
| @@ -314,6 +315,8 @@ | |||||||
|     "settingsRealmCompactView": "緊湊領域視圖", |     "settingsRealmCompactView": "緊湊領域視圖", | ||||||
|     "settingsMixedFeed": "混合動態", |     "settingsMixedFeed": "混合動態", | ||||||
|     "settingsAutoTranslate": "自動翻譯", |     "settingsAutoTranslate": "自動翻譯", | ||||||
|  |     "settingsDataSavingMode": "低數據模式", | ||||||
|  |     "dataSavingHint": "低數據模式", | ||||||
|     "settingsHideBottomNav": "隱藏底部導航", |     "settingsHideBottomNav": "隱藏底部導航", | ||||||
|     "settingsSoundEffects": "音效", |     "settingsSoundEffects": "音效", | ||||||
|     "settingsAprilFoolFeatures": "愚人節功能", |     "settingsAprilFoolFeatures": "愚人節功能", | ||||||
| @@ -811,5 +814,17 @@ | |||||||
|     "filesListAdditional": { |     "filesListAdditional": { | ||||||
|         "one": "+{} 個文件被摺疊", |         "one": "+{} 個文件被摺疊", | ||||||
|         "other": "+{} 個文件被摺疊" |         "other": "+{} 個文件被摺疊" | ||||||
|     } |     }, | ||||||
|  |     "appDetails": "應用程式詳情", | ||||||
|  |     "secrets": "密鑰", | ||||||
|  |     "appNotFound": "找不到應用程式。", | ||||||
|  |     "secretCopied": "密鑰已複製到剪貼簿。", | ||||||
|  |     "deleteSecret": "刪除密鑰", | ||||||
|  |     "deleteSecretHint": "您確定要刪除此密鑰嗎?此操作無法復原。", | ||||||
|  |     "generateSecret": "產生新密鑰", | ||||||
|  |     "createdAt": "建立於 {}", | ||||||
|  |     "newSecretGenerated": "已產生新密鑰", | ||||||
|  |     "copySecretHint": "請複製此密鑰並將其存放在安全的地方。您將無法再次看到它。", | ||||||
|  |     "expiresIn": "過期時間(秒)", | ||||||
|  |     "isOidc": "OIDC 相容" | ||||||
| } | } | ||||||
							
								
								
									
										12
									
								
								assets/icons/icon-outline.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								assets/icons/icon-outline.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | <svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" fill="none"> | ||||||
|  |     <path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="12" | ||||||
|  |         d="M54 147h86" /> | ||||||
|  |     <path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="10" | ||||||
|  |         d="M57 111s-2-4.5-2-10m22 22s-4 7-11 4m9-22s-2-4.5-2-10" /> | ||||||
|  |     <path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="12" | ||||||
|  |         d="M54 147a32 32 0 0 1-11.999-61.665A39 39 0 0 1 81 46m59 101a30 30 0 0 0 29.933-28" /> | ||||||
|  |     <circle cx="132" cy="75" r="4" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" | ||||||
|  |         stroke-width="8" /> | ||||||
|  |     <path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="10" | ||||||
|  |         d="M112.5 41.217C100.843 47.961 93 60.564 93 75c0 6.375 1.53 12.393 4.242 17.707m69.513-35.419A38.84 38.84 0 0 1 171 75c0 14.433-7.84 27.034-19.493 33.779m-.793-43.317A20.9 20.9 0 0 1 153 75c0 7.77-4.221 14.556-10.495 18.188m-21.003-36.38C115.224 60.44 111 67.226 111 75a20.9 20.9 0 0 0 2.284 9.533" /> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/icon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 108 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/media-offline.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/images/media-offline.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 461 KiB | 
| @@ -21,6 +21,6 @@ | |||||||
|   <key>CFBundleVersion</key> |   <key>CFBundleVersion</key> | ||||||
|   <string>1.0</string> |   <string>1.0</string> | ||||||
|   <key>MinimumOSVersion</key> |   <key>MinimumOSVersion</key> | ||||||
|   <string>12.0</string> |   <string>13.0</string> | ||||||
| </dict> | </dict> | ||||||
| </plist> | </plist> | ||||||
|   | |||||||
							
								
								
									
										172
									
								
								ios/Podfile.lock
									
									
									
									
									
								
							
							
						
						
									
										172
									
								
								ios/Podfile.lock
									
									
									
									
									
								
							| @@ -40,83 +40,85 @@ PODS: | |||||||
|   - file_picker (0.0.1): |   - file_picker (0.0.1): | ||||||
|     - DKImagePickerController/PhotoGallery |     - DKImagePickerController/PhotoGallery | ||||||
|     - Flutter |     - Flutter | ||||||
|   - Firebase/CoreOnly (12.0.0): |   - file_saver (0.0.1): | ||||||
|     - FirebaseCore (~> 12.0.0) |     - Flutter | ||||||
|   - Firebase/Crashlytics (12.0.0): |   - Firebase/CoreOnly (12.2.0): | ||||||
|  |     - FirebaseCore (~> 12.2.0) | ||||||
|  |   - Firebase/Crashlytics (12.2.0): | ||||||
|     - Firebase/CoreOnly |     - Firebase/CoreOnly | ||||||
|     - FirebaseCrashlytics (~> 12.0.0) |     - FirebaseCrashlytics (~> 12.2.0) | ||||||
|   - Firebase/Messaging (12.0.0): |   - Firebase/Messaging (12.2.0): | ||||||
|     - Firebase/CoreOnly |     - Firebase/CoreOnly | ||||||
|     - FirebaseMessaging (~> 12.0.0) |     - FirebaseMessaging (~> 12.2.0) | ||||||
|   - firebase_analytics (12.0.0): |   - firebase_analytics (12.0.1): | ||||||
|     - firebase_core |     - firebase_core | ||||||
|     - FirebaseAnalytics (= 12.0.0) |     - FirebaseAnalytics (= 12.2.0) | ||||||
|     - Flutter |     - Flutter | ||||||
|   - firebase_core (4.0.0): |   - firebase_core (4.1.0): | ||||||
|     - Firebase/CoreOnly (= 12.0.0) |     - Firebase/CoreOnly (= 12.2.0) | ||||||
|     - Flutter |     - Flutter | ||||||
|   - firebase_crashlytics (5.0.0): |   - firebase_crashlytics (5.0.1): | ||||||
|     - Firebase/Crashlytics (= 12.0.0) |     - Firebase/Crashlytics (= 12.2.0) | ||||||
|     - firebase_core |     - firebase_core | ||||||
|     - Flutter |     - Flutter | ||||||
|   - firebase_messaging (16.0.0): |   - firebase_messaging (16.0.1): | ||||||
|     - Firebase/Messaging (= 12.0.0) |     - Firebase/Messaging (= 12.2.0) | ||||||
|     - firebase_core |     - firebase_core | ||||||
|     - Flutter |     - Flutter | ||||||
|   - FirebaseAnalytics (12.0.0): |   - FirebaseAnalytics (12.2.0): | ||||||
|     - FirebaseAnalytics/Default (= 12.0.0) |     - FirebaseAnalytics/Default (= 12.2.0) | ||||||
|     - FirebaseCore (~> 12.0.0) |     - FirebaseCore (~> 12.2.0) | ||||||
|     - FirebaseInstallations (~> 12.0.0) |     - FirebaseInstallations (~> 12.2.0) | ||||||
|     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) |     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/MethodSwizzler (~> 8.1) |     - GoogleUtilities/MethodSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/Network (~> 8.1) |     - GoogleUtilities/Network (~> 8.1) | ||||||
|     - "GoogleUtilities/NSData+zlib (~> 8.1)" |     - "GoogleUtilities/NSData+zlib (~> 8.1)" | ||||||
|     - nanopb (~> 3.30910.0) |     - nanopb (~> 3.30910.0) | ||||||
|   - FirebaseAnalytics/Default (12.0.0): |   - FirebaseAnalytics/Default (12.2.0): | ||||||
|     - FirebaseCore (~> 12.0.0) |     - FirebaseCore (~> 12.2.0) | ||||||
|     - FirebaseInstallations (~> 12.0.0) |     - FirebaseInstallations (~> 12.2.0) | ||||||
|     - GoogleAppMeasurement/Default (= 12.0.0) |     - GoogleAppMeasurement/Default (= 12.2.0) | ||||||
|     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) |     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/MethodSwizzler (~> 8.1) |     - GoogleUtilities/MethodSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/Network (~> 8.1) |     - GoogleUtilities/Network (~> 8.1) | ||||||
|     - "GoogleUtilities/NSData+zlib (~> 8.1)" |     - "GoogleUtilities/NSData+zlib (~> 8.1)" | ||||||
|     - nanopb (~> 3.30910.0) |     - nanopb (~> 3.30910.0) | ||||||
|   - FirebaseCore (12.0.0): |   - FirebaseCore (12.2.0): | ||||||
|     - FirebaseCoreInternal (~> 12.0.0) |     - FirebaseCoreInternal (~> 12.2.0) | ||||||
|     - GoogleUtilities/Environment (~> 8.1) |     - GoogleUtilities/Environment (~> 8.1) | ||||||
|     - GoogleUtilities/Logger (~> 8.1) |     - GoogleUtilities/Logger (~> 8.1) | ||||||
|   - FirebaseCoreExtension (12.0.0): |   - FirebaseCoreExtension (12.2.0): | ||||||
|     - FirebaseCore (~> 12.0.0) |     - FirebaseCore (~> 12.2.0) | ||||||
|   - FirebaseCoreInternal (12.0.0): |   - FirebaseCoreInternal (12.2.0): | ||||||
|     - "GoogleUtilities/NSData+zlib (~> 8.1)" |     - "GoogleUtilities/NSData+zlib (~> 8.1)" | ||||||
|   - FirebaseCrashlytics (12.0.0): |   - FirebaseCrashlytics (12.2.0): | ||||||
|     - FirebaseCore (~> 12.0.0) |     - FirebaseCore (~> 12.2.0) | ||||||
|     - FirebaseInstallations (~> 12.0.0) |     - FirebaseInstallations (~> 12.2.0) | ||||||
|     - FirebaseRemoteConfigInterop (~> 12.0.0) |     - FirebaseRemoteConfigInterop (~> 12.2.0) | ||||||
|     - FirebaseSessions (~> 12.0.0) |     - FirebaseSessions (~> 12.2.0) | ||||||
|     - GoogleDataTransport (~> 10.1) |     - GoogleDataTransport (~> 10.1) | ||||||
|     - GoogleUtilities/Environment (~> 8.1) |     - GoogleUtilities/Environment (~> 8.1) | ||||||
|     - nanopb (~> 3.30910.0) |     - nanopb (~> 3.30910.0) | ||||||
|     - PromisesObjC (~> 2.4) |     - PromisesObjC (~> 2.4) | ||||||
|   - FirebaseInstallations (12.0.0): |   - FirebaseInstallations (12.2.0): | ||||||
|     - FirebaseCore (~> 12.0.0) |     - FirebaseCore (~> 12.2.0) | ||||||
|     - GoogleUtilities/Environment (~> 8.1) |     - GoogleUtilities/Environment (~> 8.1) | ||||||
|     - GoogleUtilities/UserDefaults (~> 8.1) |     - GoogleUtilities/UserDefaults (~> 8.1) | ||||||
|     - PromisesObjC (~> 2.4) |     - PromisesObjC (~> 2.4) | ||||||
|   - FirebaseMessaging (12.0.0): |   - FirebaseMessaging (12.2.0): | ||||||
|     - FirebaseCore (~> 12.0.0) |     - FirebaseCore (~> 12.2.0) | ||||||
|     - FirebaseInstallations (~> 12.0.0) |     - FirebaseInstallations (~> 12.2.0) | ||||||
|     - GoogleDataTransport (~> 10.1) |     - GoogleDataTransport (~> 10.1) | ||||||
|     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) |     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/Environment (~> 8.1) |     - GoogleUtilities/Environment (~> 8.1) | ||||||
|     - GoogleUtilities/Reachability (~> 8.1) |     - GoogleUtilities/Reachability (~> 8.1) | ||||||
|     - GoogleUtilities/UserDefaults (~> 8.1) |     - GoogleUtilities/UserDefaults (~> 8.1) | ||||||
|     - nanopb (~> 3.30910.0) |     - nanopb (~> 3.30910.0) | ||||||
|   - FirebaseRemoteConfigInterop (12.0.0) |   - FirebaseRemoteConfigInterop (12.2.0) | ||||||
|   - FirebaseSessions (12.0.0): |   - FirebaseSessions (12.2.0): | ||||||
|     - FirebaseCore (~> 12.0.0) |     - FirebaseCore (~> 12.2.0) | ||||||
|     - FirebaseCoreExtension (~> 12.0.0) |     - FirebaseCoreExtension (~> 12.2.0) | ||||||
|     - FirebaseInstallations (~> 12.0.0) |     - FirebaseInstallations (~> 12.2.0) | ||||||
|     - GoogleDataTransport (~> 10.1) |     - GoogleDataTransport (~> 10.1) | ||||||
|     - GoogleUtilities/Environment (~> 8.1) |     - GoogleUtilities/Environment (~> 8.1) | ||||||
|     - GoogleUtilities/UserDefaults (~> 8.1) |     - GoogleUtilities/UserDefaults (~> 8.1) | ||||||
| @@ -134,6 +136,8 @@ PODS: | |||||||
|     - OrderedSet (~> 6.0.3) |     - OrderedSet (~> 6.0.3) | ||||||
|   - flutter_keyboard_visibility (0.0.1): |   - flutter_keyboard_visibility (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|  |   - flutter_local_notifications (0.0.1): | ||||||
|  |     - Flutter | ||||||
|   - flutter_native_splash (2.4.3): |   - flutter_native_splash (2.4.3): | ||||||
|     - Flutter |     - Flutter | ||||||
|   - flutter_platform_alert (0.0.1): |   - flutter_platform_alert (0.0.1): | ||||||
| @@ -145,33 +149,33 @@ PODS: | |||||||
|   - flutter_udid (0.0.1): |   - flutter_udid (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|     - SAMKeychain |     - SAMKeychain | ||||||
|   - flutter_webrtc (1.0.0): |   - flutter_webrtc (1.1.0): | ||||||
|     - Flutter |     - Flutter | ||||||
|     - WebRTC-SDK (= 137.7151.02) |     - WebRTC-SDK (= 137.7151.03) | ||||||
|   - gal (1.0.0): |   - gal (1.0.0): | ||||||
|     - Flutter |     - Flutter | ||||||
|     - FlutterMacOS |     - FlutterMacOS | ||||||
|   - GoogleAdsOnDeviceConversion (2.1.0): |   - GoogleAdsOnDeviceConversion (2.3.0): | ||||||
|     - GoogleUtilities/Logger (~> 8.1) |     - GoogleUtilities/Logger (~> 8.1) | ||||||
|     - GoogleUtilities/Network (~> 8.1) |     - GoogleUtilities/Network (~> 8.1) | ||||||
|     - nanopb (~> 3.30910.0) |     - nanopb (~> 3.30910.0) | ||||||
|   - GoogleAppMeasurement/Core (12.0.0): |   - GoogleAppMeasurement/Core (12.2.0): | ||||||
|     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) |     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/MethodSwizzler (~> 8.1) |     - GoogleUtilities/MethodSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/Network (~> 8.1) |     - GoogleUtilities/Network (~> 8.1) | ||||||
|     - "GoogleUtilities/NSData+zlib (~> 8.1)" |     - "GoogleUtilities/NSData+zlib (~> 8.1)" | ||||||
|     - nanopb (~> 3.30910.0) |     - nanopb (~> 3.30910.0) | ||||||
|   - GoogleAppMeasurement/Default (12.0.0): |   - GoogleAppMeasurement/Default (12.2.0): | ||||||
|     - GoogleAdsOnDeviceConversion (= 2.1.0) |     - GoogleAdsOnDeviceConversion (= 2.3.0) | ||||||
|     - GoogleAppMeasurement/Core (= 12.0.0) |     - GoogleAppMeasurement/Core (= 12.2.0) | ||||||
|     - GoogleAppMeasurement/IdentitySupport (= 12.0.0) |     - GoogleAppMeasurement/IdentitySupport (= 12.2.0) | ||||||
|     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) |     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/MethodSwizzler (~> 8.1) |     - GoogleUtilities/MethodSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/Network (~> 8.1) |     - GoogleUtilities/Network (~> 8.1) | ||||||
|     - "GoogleUtilities/NSData+zlib (~> 8.1)" |     - "GoogleUtilities/NSData+zlib (~> 8.1)" | ||||||
|     - nanopb (~> 3.30910.0) |     - nanopb (~> 3.30910.0) | ||||||
|   - GoogleAppMeasurement/IdentitySupport (12.0.0): |   - GoogleAppMeasurement/IdentitySupport (12.2.0): | ||||||
|     - GoogleAppMeasurement/Core (= 12.0.0) |     - GoogleAppMeasurement/Core (= 12.2.0) | ||||||
|     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) |     - GoogleUtilities/AppDelegateSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/MethodSwizzler (~> 8.1) |     - GoogleUtilities/MethodSwizzler (~> 8.1) | ||||||
|     - GoogleUtilities/Network (~> 8.1) |     - GoogleUtilities/Network (~> 8.1) | ||||||
| @@ -215,7 +219,7 @@ PODS: | |||||||
|   - livekit_client (2.5.0): |   - livekit_client (2.5.0): | ||||||
|     - Flutter |     - Flutter | ||||||
|     - flutter_webrtc |     - flutter_webrtc | ||||||
|     - WebRTC-SDK (= 137.7151.02) |     - WebRTC-SDK (= 137.7151.03) | ||||||
|   - local_auth_darwin (0.0.1): |   - local_auth_darwin (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|     - FlutterMacOS |     - FlutterMacOS | ||||||
| @@ -245,12 +249,12 @@ PODS: | |||||||
|     - PromisesObjC (= 2.4.0) |     - PromisesObjC (= 2.4.0) | ||||||
|   - receive_sharing_intent (1.8.1): |   - receive_sharing_intent (1.8.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|   - record_ios (1.0.0): |   - record_ios (1.1.0): | ||||||
|     - Flutter |     - Flutter | ||||||
|   - SAMKeychain (1.5.3) |   - SAMKeychain (1.5.3) | ||||||
|   - SDWebImage (5.21.1): |   - SDWebImage (5.21.2): | ||||||
|     - SDWebImage/Core (= 5.21.1) |     - SDWebImage/Core (= 5.21.2) | ||||||
|   - SDWebImage/Core (5.21.1) |   - SDWebImage/Core (5.21.2) | ||||||
|   - share_plus (0.0.1): |   - share_plus (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|   - shared_preferences_foundation (0.0.1): |   - shared_preferences_foundation (0.0.1): | ||||||
| @@ -295,7 +299,7 @@ PODS: | |||||||
|     - Flutter |     - Flutter | ||||||
|   - wakelock_plus (0.0.1): |   - wakelock_plus (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|   - WebRTC-SDK (137.7151.02) |   - WebRTC-SDK (137.7151.03) | ||||||
|  |  | ||||||
| DEPENDENCIES: | DEPENDENCIES: | ||||||
|   - Alamofire |   - Alamofire | ||||||
| @@ -303,6 +307,7 @@ DEPENDENCIES: | |||||||
|   - 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`) | ||||||
|   - file_picker (from `.symlinks/plugins/file_picker/ios`) |   - file_picker (from `.symlinks/plugins/file_picker/ios`) | ||||||
|  |   - file_saver (from `.symlinks/plugins/file_saver/ios`) | ||||||
|   - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) |   - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) | ||||||
|   - firebase_core (from `.symlinks/plugins/firebase_core/ios`) |   - firebase_core (from `.symlinks/plugins/firebase_core/ios`) | ||||||
|   - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) |   - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) | ||||||
| @@ -311,6 +316,7 @@ DEPENDENCIES: | |||||||
|   - 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`) | ||||||
|  |   - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) | ||||||
|   - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) |   - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) | ||||||
|   - flutter_platform_alert (from `.symlinks/plugins/flutter_platform_alert/ios`) |   - flutter_platform_alert (from `.symlinks/plugins/flutter_platform_alert/ios`) | ||||||
|   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) |   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) | ||||||
| @@ -381,6 +387,8 @@ EXTERNAL SOURCES: | |||||||
|     :path: ".symlinks/plugins/device_info_plus/ios" |     :path: ".symlinks/plugins/device_info_plus/ios" | ||||||
|   file_picker: |   file_picker: | ||||||
|     :path: ".symlinks/plugins/file_picker/ios" |     :path: ".symlinks/plugins/file_picker/ios" | ||||||
|  |   file_saver: | ||||||
|  |     :path: ".symlinks/plugins/file_saver/ios" | ||||||
|   firebase_analytics: |   firebase_analytics: | ||||||
|     :path: ".symlinks/plugins/firebase_analytics/ios" |     :path: ".symlinks/plugins/firebase_analytics/ios" | ||||||
|   firebase_core: |   firebase_core: | ||||||
| @@ -397,6 +405,8 @@ EXTERNAL SOURCES: | |||||||
|     :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" |     :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" | ||||||
|   flutter_keyboard_visibility: |   flutter_keyboard_visibility: | ||||||
|     :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" |     :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" | ||||||
|  |   flutter_local_notifications: | ||||||
|  |     :path: ".symlinks/plugins/flutter_local_notifications/ios" | ||||||
|   flutter_native_splash: |   flutter_native_splash: | ||||||
|     :path: ".symlinks/plugins/flutter_native_splash/ios" |     :path: ".symlinks/plugins/flutter_native_splash/ios" | ||||||
|   flutter_platform_alert: |   flutter_platform_alert: | ||||||
| @@ -464,39 +474,41 @@ SPEC CHECKSUMS: | |||||||
|   DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c |   DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c | ||||||
|   DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 |   DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 | ||||||
|   file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be |   file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be | ||||||
|   Firebase: 800d487043c0557d9faed71477a38d9aafb08a41 |   file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6 | ||||||
|   firebase_analytics: cd56fc56f75c1df30a6ff5290cd56e230996a76d |   Firebase: 26f6f8d460603af3df970ad505b16b15f5e2e9a1 | ||||||
|   firebase_core: 633e1851ffe1b9ab875f6467a4f574c79cef02e4 |   firebase_analytics: 111ff65791a430356bd6c7e4d7339537fc6a15ae | ||||||
|   firebase_crashlytics: 2c6c1a17900a38081d938330e9f48e60ec5b255d |   firebase_core: 3ff52146406557dddd01d570e807e203ec7e1302 | ||||||
|   firebase_messaging: d17feef781edc84ebefe62624fb384358ad96361 |   firebase_crashlytics: 3637078b718a52dc9fb4d64e37c969e86b87ff6f | ||||||
|   FirebaseAnalytics: 6d790cd1b159b4eb61a99948df0934ce505a34f7 |   firebase_messaging: 3dcc998dd98e1e54af75d0cccae8606eba43553c | ||||||
|   FirebaseCore: 055f4ab117d5964158c833f3d5e7ec6d91648d4a |   FirebaseAnalytics: e04e23bc070e3014aa5cf4980f9df7ce5cd79ec8 | ||||||
|   FirebaseCoreExtension: 639afb3de6abd611952be78a794c54a47fa0f361 |   FirebaseCore: 311c48a147ad4a0ab7febbaed89e8025c67510cd | ||||||
|   FirebaseCoreInternal: dedc28e569a4be85f38f3d6af1070a2e12018d55 |   FirebaseCoreExtension: 73af080c22a2f7b44cefa391dc08f7e4ee162cb5 | ||||||
|   FirebaseCrashlytics: db75aa0cab8d00f68406fa247c32fe17ade884d7 |   FirebaseCoreInternal: 56ea29f3dad2894f81b060f706f9d53509b6ed3b | ||||||
|   FirebaseInstallations: d4c7c958f99c8860d7fcece786314ae790e2f988 |   FirebaseCrashlytics: f83cbf176d5c637ade108c0aacf1ccbd5ec499bf | ||||||
|   FirebaseMessaging: af49f8d7c0a3d2a017d9302c80946f45a7777dde |   FirebaseInstallations: 3e884b01feabdf67582a80f3250425a00979b4ed | ||||||
|   FirebaseRemoteConfigInterop: bfa0ea72ba3dc5af739777296424e46bd6f42613 |   FirebaseMessaging: 43ec73bbfedd0c385a849bb91593ab4ad4b9e48e | ||||||
|   FirebaseSessions: 4e784acda213108aafef536535cdfc03504acc42 |   FirebaseRemoteConfigInterop: 0896fd52ab72586a355c8f389ff85aaa9e5375e1 | ||||||
|   Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 |   FirebaseSessions: f4692789e770bec66ce17d772c0e9561c4f11737 | ||||||
|  |   Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 | ||||||
|   flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9 |   flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9 | ||||||
|   flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 |   flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 | ||||||
|   flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619 |   flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619 | ||||||
|  |   flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb | ||||||
|   flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf |   flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf | ||||||
|   flutter_platform_alert: bf3b5fcd4ac14bd637e20527e9c471633071afd3 |   flutter_platform_alert: bf3b5fcd4ac14bd637e20527e9c471633071afd3 | ||||||
|   flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 |   flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 | ||||||
|   flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544 |   flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544 | ||||||
|   flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9 |   flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9 | ||||||
|   flutter_webrtc: 6f7da106613d52ade777d5b4875a43f48c28b457 |   flutter_webrtc: b0b2e04411747142962164a1cfa43a1af9a0afac | ||||||
|   gal: baecd024ebfd13c441269ca7404792a7152fde89 |   gal: baecd024ebfd13c441269ca7404792a7152fde89 | ||||||
|   GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 |   GoogleAdsOnDeviceConversion: 9090c435cde08903e8dd1ba2c77fbec9e46d9afe | ||||||
|   GoogleAppMeasurement: 8f6ab04ad6ae493b53fcf56bd26323fb2f1384f3 |   GoogleAppMeasurement: 09f341dfa8527d1612a09cbfe809a242c0b737af | ||||||
|   GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 |   GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 | ||||||
|   GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 |   GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 | ||||||
|   image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a |   image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a | ||||||
|   irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486 |   irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486 | ||||||
|   Kingfisher: ff0d31a1f07bdff6a1ebb3ba08b8e6e567b6500c |   Kingfisher: ff0d31a1f07bdff6a1ebb3ba08b8e6e567b6500c | ||||||
|   livekit_client: e3b79b99405428aac439b6b76a254cd9a11dbbfb |   livekit_client: f810c81bbbc229a84f60b09e66603ac4e93f7599 | ||||||
|   local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19 |   local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19 | ||||||
|   media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 |   media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 | ||||||
|   media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 |   media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 | ||||||
| @@ -510,9 +522,9 @@ SPEC CHECKSUMS: | |||||||
|   PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 |   PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 | ||||||
|   PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 |   PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 | ||||||
|   receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 |   receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 | ||||||
|   record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b |   record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374 | ||||||
|   SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c |   SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c | ||||||
|   SDWebImage: f29024626962457f3470184232766516dee8dfea |   SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a | ||||||
|   share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a |   share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a | ||||||
|   shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 |   shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 | ||||||
|   sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418 |   sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418 | ||||||
| @@ -524,7 +536,7 @@ SPEC CHECKSUMS: | |||||||
|   url_launcher_ios: 694010445543906933d732453a59da0a173ae33d |   url_launcher_ios: 694010445543906933d732453a59da0a173ae33d | ||||||
|   volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 |   volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 | ||||||
|   wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 |   wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 | ||||||
|   WebRTC-SDK: d20de357dcbf7c9696b124b39f3ff62125107e4b |   WebRTC-SDK: 69d4e56b0b4b27d788e87bab9b9a1326ed05b1e3 | ||||||
|  |  | ||||||
| PODFILE CHECKSUM: c818292390b02fa379036ea099713a332bd7193f | PODFILE CHECKSUM: c818292390b02fa379036ea099713a332bd7193f | ||||||
|  |  | ||||||
|   | |||||||
| @@ -853,7 +853,7 @@ | |||||||
| 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||||
| 				GCC_WARN_UNUSED_FUNCTION = YES; | 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||||
| 				GCC_WARN_UNUSED_VARIABLE = YES; | 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | 				IPHONEOS_DEPLOYMENT_TARGET = 13.0; | ||||||
| 				MTL_ENABLE_DEBUG_INFO = NO; | 				MTL_ENABLE_DEBUG_INFO = NO; | ||||||
| 				SDKROOT = iphoneos; | 				SDKROOT = iphoneos; | ||||||
| 				SUPPORTED_PLATFORMS = iphoneos; | 				SUPPORTED_PLATFORMS = iphoneos; | ||||||
| @@ -897,6 +897,7 @@ | |||||||
| 				CODE_SIGN_STYLE = Automatic; | 				CODE_SIGN_STYLE = Automatic; | ||||||
| 				CURRENT_PROJECT_VERSION = 1; | 				CURRENT_PROJECT_VERSION = 1; | ||||||
| 				GENERATE_INFOPLIST_FILE = YES; | 				GENERATE_INFOPLIST_FILE = YES; | ||||||
|  | 				IPHONEOS_DEPLOYMENT_TARGET = 15.0; | ||||||
| 				MARKETING_VERSION = 1.0; | 				MARKETING_VERSION = 1.0; | ||||||
| 				PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests; | 				PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests; | ||||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
| @@ -915,6 +916,7 @@ | |||||||
| 				CODE_SIGN_STYLE = Automatic; | 				CODE_SIGN_STYLE = Automatic; | ||||||
| 				CURRENT_PROJECT_VERSION = 1; | 				CURRENT_PROJECT_VERSION = 1; | ||||||
| 				GENERATE_INFOPLIST_FILE = YES; | 				GENERATE_INFOPLIST_FILE = YES; | ||||||
|  | 				IPHONEOS_DEPLOYMENT_TARGET = 15.0; | ||||||
| 				MARKETING_VERSION = 1.0; | 				MARKETING_VERSION = 1.0; | ||||||
| 				PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests; | 				PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests; | ||||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
| @@ -931,6 +933,7 @@ | |||||||
| 				CODE_SIGN_STYLE = Automatic; | 				CODE_SIGN_STYLE = Automatic; | ||||||
| 				CURRENT_PROJECT_VERSION = 1; | 				CURRENT_PROJECT_VERSION = 1; | ||||||
| 				GENERATE_INFOPLIST_FILE = YES; | 				GENERATE_INFOPLIST_FILE = YES; | ||||||
|  | 				IPHONEOS_DEPLOYMENT_TARGET = 15.0; | ||||||
| 				MARKETING_VERSION = 1.0; | 				MARKETING_VERSION = 1.0; | ||||||
| 				PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests; | 				PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests; | ||||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
| @@ -1078,7 +1081,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 = 13.0; | 				IPHONEOS_DEPLOYMENT_TARGET = 15.0; | ||||||
| 				LD_RUNPATH_SEARCH_PATHS = ( | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
| 					"$(inherited)", | 					"$(inherited)", | ||||||
| 					"@executable_path/Frameworks", | 					"@executable_path/Frameworks", | ||||||
| @@ -1121,7 +1124,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 = 13.0; | 				IPHONEOS_DEPLOYMENT_TARGET = 15.0; | ||||||
| 				LD_RUNPATH_SEARCH_PATHS = ( | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
| 					"$(inherited)", | 					"$(inherited)", | ||||||
| 					"@executable_path/Frameworks", | 					"@executable_path/Frameworks", | ||||||
| @@ -1161,7 +1164,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 = 13.0; | 				IPHONEOS_DEPLOYMENT_TARGET = 15.0; | ||||||
| 				LD_RUNPATH_SEARCH_PATHS = ( | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
| 					"$(inherited)", | 					"$(inherited)", | ||||||
| 					"@executable_path/Frameworks", | 					"@executable_path/Frameworks", | ||||||
| @@ -1348,7 +1351,7 @@ | |||||||
| 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||||
| 				GCC_WARN_UNUSED_FUNCTION = YES; | 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||||
| 				GCC_WARN_UNUSED_VARIABLE = YES; | 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | 				IPHONEOS_DEPLOYMENT_TARGET = 13.0; | ||||||
| 				MTL_ENABLE_DEBUG_INFO = YES; | 				MTL_ENABLE_DEBUG_INFO = YES; | ||||||
| 				ONLY_ACTIVE_ARCH = YES; | 				ONLY_ACTIVE_ARCH = YES; | ||||||
| 				SDKROOT = iphoneos; | 				SDKROOT = iphoneos; | ||||||
| @@ -1399,7 +1402,7 @@ | |||||||
| 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||||
| 				GCC_WARN_UNUSED_FUNCTION = YES; | 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||||
| 				GCC_WARN_UNUSED_VARIABLE = YES; | 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | 				IPHONEOS_DEPLOYMENT_TARGET = 13.0; | ||||||
| 				MTL_ENABLE_DEBUG_INFO = NO; | 				MTL_ENABLE_DEBUG_INFO = NO; | ||||||
| 				SDKROOT = iphoneos; | 				SDKROOT = iphoneos; | ||||||
| 				SUPPORTED_PLATFORMS = iphoneos; | 				SUPPORTED_PLATFORMS = iphoneos; | ||||||
|   | |||||||
| @@ -47,6 +47,7 @@ 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.categoryIdentifier = "REPLYABLE_MESSAGE" | ||||||
|             try handleMessagingNotification(request: request, content: content) |             try handleMessagingNotification(request: request, content: content) | ||||||
|         default: |         default: | ||||||
|             try handleDefaultNotification(content: content) |             try handleDefaultNotification(content: content) | ||||||
| @@ -60,8 +61,6 @@ class NotificationService: UNNotificationServiceExtension { | |||||||
|          |          | ||||||
|         let pfpIdentifier = meta["pfp"] as? String |         let pfpIdentifier = meta["pfp"] as? String | ||||||
|          |          | ||||||
|         content.categoryIdentifier = "REPLYABLE_MESSAGE" |  | ||||||
|          |  | ||||||
|         let metaCopy = meta as? [String: Any] ?? [:] |         let metaCopy = meta as? [String: Any] ?? [:] | ||||||
|         let pfpUrl = pfpIdentifier != nil ? getAttachmentUrl(for: pfpIdentifier!) : nil |         let pfpUrl = pfpIdentifier != nil ? getAttachmentUrl(for: pfpIdentifier!) : nil | ||||||
|          |          | ||||||
|   | |||||||
| @@ -68,6 +68,34 @@ class AppDatabase extends _$AppDatabase { | |||||||
|     return (delete(chatMessages)..where((m) => m.id.equals(id))).go(); |     return (delete(chatMessages)..where((m) => m.id.equals(id))).go(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   Future<int> getTotalMessagesForRoom(String roomId) { | ||||||
|  |     return (select(chatMessages)..where((m) => m.roomId.equals(roomId))).get().then((list) => list.length); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<List<LocalChatMessage>> searchMessages( | ||||||
|  |     String roomId, | ||||||
|  |     String query, | ||||||
|  |   ) async { | ||||||
|  |     var selectStatement = select(chatMessages) | ||||||
|  |       ..where((m) => m.roomId.equals(roomId)); | ||||||
|  |  | ||||||
|  |     if (query.isNotEmpty) { | ||||||
|  |       selectStatement = | ||||||
|  |           selectStatement | ||||||
|  |             ..where((m) => m.content.like('%${query.toLowerCase()}%')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     final messages = | ||||||
|  |         await (selectStatement | ||||||
|  |               ..orderBy([(m) => OrderingTerm.desc(m.createdAt)])) | ||||||
|  |             .get(); | ||||||
|  |     return messages.map((msg) => companionToMessage(msg)).toList(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // Convert between Drift and model objects |   // Convert between Drift and model objects | ||||||
|   ChatMessagesCompanion messageToCompanion(LocalChatMessage message) { |   ChatMessagesCompanion messageToCompanion(LocalChatMessage message) { | ||||||
|     return ChatMessagesCompanion( |     return ChatMessagesCompanion( | ||||||
|   | |||||||
| @@ -1,484 +0,0 @@ | |||||||
| import 'package:dio/dio.dart'; |  | ||||||
| import 'package:island/database/drift_db.dart'; |  | ||||||
| import 'package:island/database/message.dart'; |  | ||||||
| import 'package:island/models/chat.dart'; |  | ||||||
| import 'package:island/models/file.dart'; |  | ||||||
| import 'package:island/services/file.dart'; |  | ||||||
| import 'package:island/widgets/alert.dart'; |  | ||||||
| import 'package:uuid/uuid.dart'; |  | ||||||
|  |  | ||||||
| class MessageRepository { |  | ||||||
|   final SnChatRoom room; |  | ||||||
|   final SnChatMember identity; |  | ||||||
|   final Dio _apiClient; |  | ||||||
|   final AppDatabase _database; |  | ||||||
|  |  | ||||||
|   final Map<String, LocalChatMessage> pendingMessages = {}; |  | ||||||
|   final Map<String, Map<int, double>> fileUploadProgress = {}; |  | ||||||
|   int? _totalCount; |  | ||||||
|  |  | ||||||
|   MessageRepository(this.room, this.identity, this._apiClient, this._database); |  | ||||||
|  |  | ||||||
|   Future<LocalChatMessage?> getLastMessages() async { |  | ||||||
|     final dbMessages = await _database.getMessagesForRoom( |  | ||||||
|       room.id, |  | ||||||
|       offset: 0, |  | ||||||
|       limit: 1, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     if (dbMessages.isEmpty) { |  | ||||||
|       return null; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return _database.companionToMessage(dbMessages.first); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<bool> syncMessages() async { |  | ||||||
|     final lastMessage = await getLastMessages(); |  | ||||||
|     if (lastMessage == null) return false; |  | ||||||
|     try { |  | ||||||
|       final resp = await _apiClient.post( |  | ||||||
|         '/sphere/chat/${room.id}/sync', |  | ||||||
|         data: { |  | ||||||
|           'last_sync_timestamp': |  | ||||||
|               lastMessage.toRemoteMessage().updatedAt.millisecondsSinceEpoch, |  | ||||||
|         }, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       final response = MessageSyncResponse.fromJson(resp.data); |  | ||||||
|       for (final change in response.changes) { |  | ||||||
|         switch (change.action) { |  | ||||||
|           case MessageChangeAction.create: |  | ||||||
|             await receiveMessage(change.message!); |  | ||||||
|             break; |  | ||||||
|           case MessageChangeAction.update: |  | ||||||
|             await receiveMessageUpdate(change.message!); |  | ||||||
|             break; |  | ||||||
|           case MessageChangeAction.delete: |  | ||||||
|             await receiveMessageDeletion(change.messageId.toString()); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } catch (err) { |  | ||||||
|       showErrorAlert(err); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<List<LocalChatMessage>> listMessages({ |  | ||||||
|     int offset = 0, |  | ||||||
|     int take = 20, |  | ||||||
|     bool synced = false, |  | ||||||
|   }) async { |  | ||||||
|     try { |  | ||||||
|       // For initial load, fetch latest messages in the background to sync. |  | ||||||
|       if (offset == 0 && !synced) { |  | ||||||
|         // Not awaiting this is intentional, for a quicker UI response. |  | ||||||
|         // The UI should rely on a stream from the database to get updates. |  | ||||||
|         _fetchAndCacheMessages(room.id, offset: 0, take: take).catchError((_) { |  | ||||||
|           // Best effort, errors will be handled by later fetches. |  | ||||||
|           return <LocalChatMessage>[]; |  | ||||||
|         }); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       final localMessages = await _getCachedMessages( |  | ||||||
|         room.id, |  | ||||||
|         offset: offset, |  | ||||||
|         take: take, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       // If local cache has messages, return them. This is the common case for scrolling up. |  | ||||||
|       if (localMessages.isNotEmpty) { |  | ||||||
|         return localMessages; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // If local cache is empty, we've probably reached the end of cached history. |  | ||||||
|       // Fetch from remote. This will also be hit on first load if cache is empty. |  | ||||||
|       return await _fetchAndCacheMessages(room.id, offset: offset, take: take); |  | ||||||
|     } catch (e) { |  | ||||||
|       // Final fallback to cache in case of network errors during fetch. |  | ||||||
|       final localMessages = await _getCachedMessages( |  | ||||||
|         room.id, |  | ||||||
|         offset: offset, |  | ||||||
|         take: take, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       if (localMessages.isNotEmpty) { |  | ||||||
|         return localMessages; |  | ||||||
|       } |  | ||||||
|       rethrow; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<List<LocalChatMessage>> _getCachedMessages( |  | ||||||
|     String roomId, { |  | ||||||
|     int offset = 0, |  | ||||||
|     int take = 20, |  | ||||||
|   }) async { |  | ||||||
|     // Get messages from local database |  | ||||||
|     final dbMessages = await _database.getMessagesForRoom( |  | ||||||
|       roomId, |  | ||||||
|       offset: offset, |  | ||||||
|       limit: take, |  | ||||||
|     ); |  | ||||||
|     final dbLocalMessages = |  | ||||||
|         dbMessages.map(_database.companionToMessage).toList(); |  | ||||||
|  |  | ||||||
|     // Combine with pending messages for the first page |  | ||||||
|     if (offset == 0) { |  | ||||||
|       final pendingForRoom = |  | ||||||
|           pendingMessages.values.where((msg) => msg.roomId == roomId).toList(); |  | ||||||
|  |  | ||||||
|       final allMessages = [...pendingForRoom, ...dbLocalMessages]; |  | ||||||
|       allMessages.sort((a, b) => b.createdAt.compareTo(a.createdAt)); |  | ||||||
|  |  | ||||||
|       // Remove duplicates by ID, preserving the order |  | ||||||
|       final uniqueMessages = <LocalChatMessage>[]; |  | ||||||
|       final seenIds = <String>{}; |  | ||||||
|       for (final message in allMessages) { |  | ||||||
|         if (seenIds.add(message.id)) { |  | ||||||
|           uniqueMessages.add(message); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       return uniqueMessages; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return dbLocalMessages; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<List<LocalChatMessage>> _fetchAndCacheMessages( |  | ||||||
|     String roomId, { |  | ||||||
|     int offset = 0, |  | ||||||
|     int take = 20, |  | ||||||
|   }) async { |  | ||||||
|     // Use cached total count if available, otherwise fetch it |  | ||||||
|     if (_totalCount == null) { |  | ||||||
|       final response = await _apiClient.get( |  | ||||||
|         '/sphere/chat/$roomId/messages', |  | ||||||
|         queryParameters: {'offset': 0, 'take': 1}, |  | ||||||
|       ); |  | ||||||
|       _totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (offset >= _totalCount!) { |  | ||||||
|       return []; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     final response = await _apiClient.get( |  | ||||||
|       '/sphere/chat/$roomId/messages', |  | ||||||
|       queryParameters: {'offset': offset, 'take': take}, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     final List<dynamic> data = response.data; |  | ||||||
|     // Update total count from response headers |  | ||||||
|     _totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0'); |  | ||||||
|  |  | ||||||
|     final messages = |  | ||||||
|         data.map((json) { |  | ||||||
|           final remoteMessage = SnChatMessage.fromJson(json); |  | ||||||
|           return LocalChatMessage.fromRemoteMessage( |  | ||||||
|             remoteMessage, |  | ||||||
|             MessageStatus.sent, |  | ||||||
|           ); |  | ||||||
|         }).toList(); |  | ||||||
|  |  | ||||||
|     for (final message in messages) { |  | ||||||
|       await _database.saveMessage(_database.messageToCompanion(message)); |  | ||||||
|       if (message.nonce != null) { |  | ||||||
|         pendingMessages.removeWhere( |  | ||||||
|           (_, pendingMsg) => pendingMsg.nonce == message.nonce, |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return messages; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<LocalChatMessage> sendMessage( |  | ||||||
|     String token, |  | ||||||
|     String baseUrl, |  | ||||||
|     String roomId, |  | ||||||
|     String content, |  | ||||||
|     String nonce, { |  | ||||||
|     required List<UniversalFile> attachments, |  | ||||||
|     Map<String, dynamic>? meta, |  | ||||||
|     SnChatMessage? replyingTo, |  | ||||||
|     SnChatMessage? forwardingTo, |  | ||||||
|     SnChatMessage? editingTo, |  | ||||||
|     Function(LocalChatMessage)? onPending, |  | ||||||
|     Function(String, Map<int, double>)? onProgress, |  | ||||||
|   }) async { |  | ||||||
|     // Generate a unique nonce for this message |  | ||||||
|     final nonce = const Uuid().v4(); |  | ||||||
|  |  | ||||||
|     // Create a local message with pending status |  | ||||||
|     final mockMessage = SnChatMessage( |  | ||||||
|       id: 'pending_$nonce', |  | ||||||
|       chatRoomId: roomId, |  | ||||||
|       senderId: identity.id, |  | ||||||
|       content: content, |  | ||||||
|       createdAt: DateTime.now(), |  | ||||||
|       updatedAt: DateTime.now(), |  | ||||||
|       nonce: nonce, |  | ||||||
|       sender: identity, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     final localMessage = LocalChatMessage.fromRemoteMessage( |  | ||||||
|       mockMessage, |  | ||||||
|       MessageStatus.pending, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     // Store in memory and database |  | ||||||
|     pendingMessages[localMessage.id] = localMessage; |  | ||||||
|     fileUploadProgress[localMessage.id] = {}; |  | ||||||
|     await _database.saveMessage(_database.messageToCompanion(localMessage)); |  | ||||||
|     onPending?.call(localMessage); |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|       var cloudAttachments = List.empty(growable: true); |  | ||||||
|       // Upload files |  | ||||||
|       for (var idx = 0; idx < attachments.length; idx++) { |  | ||||||
|         final cloudFile = |  | ||||||
|             await putMediaToCloud( |  | ||||||
|               fileData: attachments[idx], |  | ||||||
|               atk: token, |  | ||||||
|               baseUrl: baseUrl, |  | ||||||
|               filename: attachments[idx].data.name ?? 'Post media', |  | ||||||
|               mimetype: |  | ||||||
|                   attachments[idx].data.mimeType ?? |  | ||||||
|                   switch (attachments[idx].type) { |  | ||||||
|                     UniversalFileType.image => 'image/unknown', |  | ||||||
|                     UniversalFileType.video => 'video/unknown', |  | ||||||
|                     UniversalFileType.audio => 'audio/unknown', |  | ||||||
|                     UniversalFileType.file => 'application/octet-stream', |  | ||||||
|                   }, |  | ||||||
|               onProgress: (progress, _) { |  | ||||||
|                 fileUploadProgress[localMessage.id]?[idx] = progress; |  | ||||||
|                 onProgress?.call( |  | ||||||
|                   localMessage.id, |  | ||||||
|                   fileUploadProgress[localMessage.id] ?? {}, |  | ||||||
|                 ); |  | ||||||
|               }, |  | ||||||
|             ).future; |  | ||||||
|         if (cloudFile == null) { |  | ||||||
|           throw ArgumentError('Failed to upload the file...'); |  | ||||||
|         } |  | ||||||
|         cloudAttachments.add(cloudFile); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // Send to server |  | ||||||
|       final response = await _apiClient.request( |  | ||||||
|         editingTo == null |  | ||||||
|             ? '/sphere/chat/$roomId/messages' |  | ||||||
|             : '/sphere/chat/$roomId/messages/${editingTo.id}', |  | ||||||
|         data: { |  | ||||||
|           'content': content, |  | ||||||
|           'attachments_id': cloudAttachments.map((e) => e.id).toList(), |  | ||||||
|           'replied_message_id': replyingTo?.id, |  | ||||||
|           'forwarded_message_id': forwardingTo?.id, |  | ||||||
|           'meta': meta, |  | ||||||
|           'nonce': nonce, |  | ||||||
|         }, |  | ||||||
|         options: Options(method: editingTo == null ? 'POST' : 'PATCH'), |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       // Update with server response |  | ||||||
|       final remoteMessage = SnChatMessage.fromJson(response.data); |  | ||||||
|       final updatedMessage = LocalChatMessage.fromRemoteMessage( |  | ||||||
|         remoteMessage, |  | ||||||
|         MessageStatus.sent, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       // Remove from pending and update in database |  | ||||||
|       pendingMessages.remove(localMessage.id); |  | ||||||
|       await _database.deleteMessage(localMessage.id); |  | ||||||
|       await _database.saveMessage(_database.messageToCompanion(updatedMessage)); |  | ||||||
|  |  | ||||||
|       return updatedMessage; |  | ||||||
|     } catch (e) { |  | ||||||
|       // Update status to failed |  | ||||||
|       localMessage.status = MessageStatus.failed; |  | ||||||
|       pendingMessages[localMessage.id] = localMessage; |  | ||||||
|       await _database.updateMessageStatus( |  | ||||||
|         localMessage.id, |  | ||||||
|         MessageStatus.failed, |  | ||||||
|       ); |  | ||||||
|       rethrow; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<LocalChatMessage> retryMessage(String pendingMessageId) async { |  | ||||||
|     final message = await getMessageById(pendingMessageId); |  | ||||||
|     if (message == null) { |  | ||||||
|       throw Exception('Message not found'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Update status back to pending |  | ||||||
|     message.status = MessageStatus.pending; |  | ||||||
|     pendingMessages[pendingMessageId] = message; |  | ||||||
|     await _database.updateMessageStatus( |  | ||||||
|       pendingMessageId, |  | ||||||
|       MessageStatus.pending, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|       // Send to server |  | ||||||
|       var remoteMessage = message.toRemoteMessage(); |  | ||||||
|       final response = await _apiClient.post( |  | ||||||
|         '/sphere/chat/${message.roomId}/messages', |  | ||||||
|         data: { |  | ||||||
|           'content': remoteMessage.content, |  | ||||||
|           'attachments_id': remoteMessage.attachments, |  | ||||||
|           'meta': remoteMessage.meta, |  | ||||||
|           'nonce': message.nonce, |  | ||||||
|         }, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       // Update with server response |  | ||||||
|       remoteMessage = SnChatMessage.fromJson(response.data); |  | ||||||
|       final updatedMessage = LocalChatMessage.fromRemoteMessage( |  | ||||||
|         remoteMessage, |  | ||||||
|         MessageStatus.sent, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       // Remove from pending and update in database |  | ||||||
|       pendingMessages.remove(pendingMessageId); |  | ||||||
|       await _database.deleteMessage(pendingMessageId); |  | ||||||
|       await _database.saveMessage(_database.messageToCompanion(updatedMessage)); |  | ||||||
|  |  | ||||||
|       return updatedMessage; |  | ||||||
|     } catch (e) { |  | ||||||
|       // Update status to failed |  | ||||||
|       message.status = MessageStatus.failed; |  | ||||||
|       pendingMessages[pendingMessageId] = message; |  | ||||||
|       await _database.updateMessageStatus( |  | ||||||
|         pendingMessageId, |  | ||||||
|         MessageStatus.failed, |  | ||||||
|       ); |  | ||||||
|       rethrow; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<LocalChatMessage> receiveMessage(SnChatMessage remoteMessage) async { |  | ||||||
|     final localMessage = LocalChatMessage.fromRemoteMessage( |  | ||||||
|       remoteMessage, |  | ||||||
|       MessageStatus.sent, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     if (remoteMessage.nonce != null) { |  | ||||||
|       pendingMessages.removeWhere( |  | ||||||
|         (_, pendingMsg) => pendingMsg.nonce == remoteMessage.nonce, |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     await _database.saveMessage(_database.messageToCompanion(localMessage)); |  | ||||||
|     return localMessage; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<LocalChatMessage> receiveMessageUpdate( |  | ||||||
|     SnChatMessage remoteMessage, |  | ||||||
|   ) async { |  | ||||||
|     final localMessage = LocalChatMessage.fromRemoteMessage( |  | ||||||
|       remoteMessage, |  | ||||||
|       MessageStatus.sent, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     await _database.updateMessage(_database.messageToCompanion(localMessage)); |  | ||||||
|     return localMessage; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<void> receiveMessageDeletion(String messageId) async { |  | ||||||
|     // Remove from pending messages if exists |  | ||||||
|     pendingMessages.remove(messageId); |  | ||||||
|  |  | ||||||
|     // Delete from local database |  | ||||||
|     await _database.deleteMessage(messageId); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<LocalChatMessage> updateMessage( |  | ||||||
|     String messageId, |  | ||||||
|     String content, { |  | ||||||
|     List<SnCloudFile>? attachments, |  | ||||||
|     Map<String, dynamic>? meta, |  | ||||||
|   }) async { |  | ||||||
|     final message = pendingMessages[messageId]; |  | ||||||
|     if (message != null) { |  | ||||||
|       // Update pending message |  | ||||||
|       final rmMessage = message.toRemoteMessage(); |  | ||||||
|       final updatedRemoteMessage = rmMessage.copyWith( |  | ||||||
|         content: content, |  | ||||||
|         meta: meta ?? rmMessage.meta, |  | ||||||
|       ); |  | ||||||
|       final updatedLocalMessage = LocalChatMessage.fromRemoteMessage( |  | ||||||
|         updatedRemoteMessage, |  | ||||||
|         MessageStatus.pending, |  | ||||||
|       ); |  | ||||||
|       pendingMessages[messageId] = updatedLocalMessage; |  | ||||||
|       await _database.updateMessage( |  | ||||||
|         _database.messageToCompanion(updatedLocalMessage), |  | ||||||
|       ); |  | ||||||
|       return message; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|       // Update on server |  | ||||||
|       final response = await _apiClient.put( |  | ||||||
|         '/sphere/chat/${room.id}/messages/$messageId', |  | ||||||
|         data: {'content': content, 'attachments': attachments, 'meta': meta}, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       // Update local copy |  | ||||||
|       final remoteMessage = SnChatMessage.fromJson(response.data); |  | ||||||
|       final updatedMessage = LocalChatMessage.fromRemoteMessage( |  | ||||||
|         remoteMessage, |  | ||||||
|         MessageStatus.sent, |  | ||||||
|       ); |  | ||||||
|       await _database.updateMessage( |  | ||||||
|         _database.messageToCompanion(updatedMessage), |  | ||||||
|       ); |  | ||||||
|       return updatedMessage; |  | ||||||
|     } catch (e) { |  | ||||||
|       rethrow; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<void> deleteMessage(String messageId) async { |  | ||||||
|     try { |  | ||||||
|       await _apiClient.delete('/sphere/chat/${room.id}/messages/$messageId'); |  | ||||||
|       pendingMessages.remove(messageId); |  | ||||||
|       await _database.deleteMessage(messageId); |  | ||||||
|     } catch (e) { |  | ||||||
|       rethrow; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Future<LocalChatMessage?> getMessageById(String messageId) async { |  | ||||||
|     try { |  | ||||||
|       // Attempt to get the message from the local database |  | ||||||
|       final localMessage = |  | ||||||
|           await (_database.select(_database.chatMessages) |  | ||||||
|             ..where((tbl) => tbl.id.equals(messageId))).getSingleOrNull(); |  | ||||||
|       if (localMessage != null) { |  | ||||||
|         return _database.companionToMessage(localMessage); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // If not found locally, fetch from the server |  | ||||||
|       final response = await _apiClient.get( |  | ||||||
|         '/sphere/chat/${room.id}/messages/$messageId', |  | ||||||
|       ); |  | ||||||
|       final remoteMessage = SnChatMessage.fromJson(response.data); |  | ||||||
|       final message = LocalChatMessage.fromRemoteMessage( |  | ||||||
|         remoteMessage, |  | ||||||
|         MessageStatus.sent, |  | ||||||
|       ); |  | ||||||
|  |  | ||||||
|       // Save the fetched message to the local database |  | ||||||
|       await _database.saveMessage(_database.messageToCompanion(message)); |  | ||||||
|       return message; |  | ||||||
|     } catch (e) { |  | ||||||
|       if (e is DioException) return null; |  | ||||||
|       // Handle errors |  | ||||||
|       rethrow; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -8,7 +8,7 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart'; | |||||||
| import 'package:firebase_messaging/firebase_messaging.dart'; | import 'package:firebase_messaging/firebase_messaging.dart'; | ||||||
| import 'package:flutter/foundation.dart'; | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter/services.dart'; |  | ||||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| @@ -30,7 +30,6 @@ import 'package:shared_preferences/shared_preferences.dart'; | |||||||
| import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; | import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; | ||||||
| import 'package:flutter_native_splash/flutter_native_splash.dart'; | import 'package:flutter_native_splash/flutter_native_splash.dart'; | ||||||
| import 'package:url_launcher/url_launcher_string.dart'; | import 'package:url_launcher/url_launcher_string.dart'; | ||||||
| import 'package:flutter_langdetect/flutter_langdetect.dart' as langdetect; |  | ||||||
|  |  | ||||||
| @pragma('vm:entry-point') | @pragma('vm:entry-point') | ||||||
| Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { | Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { | ||||||
| @@ -52,7 +51,6 @@ void main() async { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   try { |   try { | ||||||
|     await langdetect.initLangDetect(); |  | ||||||
|     await EasyLocalization.ensureInitialized(); |     await EasyLocalization.ensureInitialized(); | ||||||
|  |  | ||||||
|     if (kIsWeb || !Platform.isLinux) { |     if (kIsWeb || !Platform.isLinux) { | ||||||
| @@ -64,7 +62,8 @@ void main() async { | |||||||
|       ); |       ); | ||||||
|       // Although previous if case checked this. Still check is web or not |       // Although previous if case checked this. Still check is web or not | ||||||
|       // Otherwise the web platform will broke due to there is no Platform api on the web |       // Otherwise the web platform will broke due to there is no Platform api on the web | ||||||
|       if (kIsWeb || !Platform.isWindows) { |       // Skip crashlytics setup on debug mode to prevent unexpected report to firebase | ||||||
|  |       if ((kIsWeb || !Platform.isWindows) && !kDebugMode) { | ||||||
|         FlutterError.onError = |         FlutterError.onError = | ||||||
|             FirebaseCrashlytics.instance.recordFlutterFatalError; |             FirebaseCrashlytics.instance.recordFlutterFatalError; | ||||||
|         PlatformDispatcher.instance.onError = (error, stack) { |         PlatformDispatcher.instance.onError = (error, stack) { | ||||||
| @@ -168,12 +167,12 @@ class IslandApp extends HookConsumerWidget { | |||||||
|     final theme = ref.watch(themeProvider); |     final theme = ref.watch(themeProvider); | ||||||
|  |  | ||||||
|     void handleMessage(RemoteMessage notification) { |     void handleMessage(RemoteMessage notification) { | ||||||
|       if (notification.data['action_uri'] != null) { |       if (notification.data['meta']?['action_uri'] != null) { | ||||||
|         var uri = notification.data['action_uri'] as String; |         var uri = notification.data['meta']['action_uri'] as String; | ||||||
|         if (uri.startsWith('/')) { |         if (uri.startsWith('/')) { | ||||||
|           // In-app routes |           // In-app routes | ||||||
|           final router = ref.read(routerProvider); |           final router = ref.read(routerProvider); | ||||||
|           router.go(notification.data['action_uri']); |           router.push(notification.data['meta']['action_uri']); | ||||||
|         } else { |         } else { | ||||||
|           // External links |           // External links | ||||||
|           launchUrlString(uri); |           launchUrlString(uri); | ||||||
| @@ -185,27 +184,6 @@ class IslandApp extends HookConsumerWidget { | |||||||
|       if (!kIsWeb && Platform.isLinux) { |       if (!kIsWeb && Platform.isLinux) { | ||||||
|         return null; |         return null; | ||||||
|       } |       } | ||||||
|       const channel = MethodChannel('dev.solsynth.solian/notifications'); |  | ||||||
|  |  | ||||||
|       Future<void> handleInitialLink() async { |  | ||||||
|         final String? link = await channel.invokeMethod('initialLink'); |  | ||||||
|         if (link != null) { |  | ||||||
|           final router = ref.read(routerProvider); |  | ||||||
|           router.go(link); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (!kIsWeb && Platform.isAndroid) { |  | ||||||
|         handleInitialLink(); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       channel.setMethodCallHandler((call) async { |  | ||||||
|         if (call.method == 'newLink') { |  | ||||||
|           final String link = call.arguments; |  | ||||||
|           final router = ref.read(routerProvider); |  | ||||||
|           router.go(link); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|  |  | ||||||
|       // When the app is opened from a terminated state. |       // When the app is opened from a terminated state. | ||||||
|       FirebaseMessaging.instance.getInitialMessage().then((message) { |       FirebaseMessaging.instance.getInitialMessage().then((message) { | ||||||
| @@ -245,6 +223,7 @@ class IslandApp extends HookConsumerWidget { | |||||||
|           if (user.value != null) { |           if (user.value != null) { | ||||||
|             final apiClient = ref.read(apiClientProvider); |             final apiClient = ref.read(apiClientProvider); | ||||||
|             subscribePushNotification(apiClient); |             subscribePushNotification(apiClient); | ||||||
|  |             initializeLocalNotifications(); | ||||||
|             final wsNotifier = ref.read(websocketStateProvider.notifier); |             final wsNotifier = ref.read(websocketStateProvider.notifier); | ||||||
|             wsNotifier.connect(); |             wsNotifier.connect(); | ||||||
|           } |           } | ||||||
| @@ -261,6 +240,7 @@ class IslandApp extends HookConsumerWidget { | |||||||
|       themeMode: ThemeMode.system, |       themeMode: ThemeMode.system, | ||||||
|       routerConfig: router, |       routerConfig: router, | ||||||
|       supportedLocales: context.supportedLocales, |       supportedLocales: context.supportedLocales, | ||||||
|  |       scrollBehavior: AppScrollBehavior(), | ||||||
|       localizationsDelegates: [ |       localizationsDelegates: [ | ||||||
|         ...context.localizationDelegates, |         ...context.localizationDelegates, | ||||||
|         CroppyLocalizations.delegate, |         CroppyLocalizations.delegate, | ||||||
|   | |||||||
| @@ -1,9 +1,10 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
|  | import 'package:island/models/auth.dart'; | ||||||
| import 'package:island/models/file.dart'; | import 'package:island/models/file.dart'; | ||||||
| import 'package:island/models/wallet.dart'; | import 'package:island/models/wallet.dart'; | ||||||
| 
 | 
 | ||||||
| part 'user.freezed.dart'; | part 'account.freezed.dart'; | ||||||
| part 'user.g.dart'; | part 'account.g.dart'; | ||||||
| 
 | 
 | ||||||
| @freezed | @freezed | ||||||
| sealed class SnAccount with _$SnAccount { | sealed class SnAccount with _$SnAccount { | ||||||
| @@ -12,7 +13,9 @@ sealed class SnAccount with _$SnAccount { | |||||||
|     required String name, |     required String name, | ||||||
|     required String nick, |     required String nick, | ||||||
|     required String language, |     required String language, | ||||||
|  |     @Default("") String region, | ||||||
|     required bool isSuperuser, |     required bool isSuperuser, | ||||||
|  |     required String? automatedId, | ||||||
|     required SnAccountProfile profile, |     required SnAccountProfile profile, | ||||||
|     required SnWalletSubscriptionRef? perkSubscription, |     required SnWalletSubscriptionRef? perkSubscription, | ||||||
|     @Default([]) List<SnAccountBadge> badges, |     @Default([]) List<SnAccountBadge> badges, | ||||||
| @@ -69,6 +72,8 @@ sealed class SnAccountProfile with _$SnAccountProfile { | |||||||
|     SnAccountBadge? activeBadge, |     SnAccountBadge? activeBadge, | ||||||
|     required int experience, |     required int experience, | ||||||
|     required int level, |     required int level, | ||||||
|  |     @Default(100) double socialCredits, | ||||||
|  |     @Default(0) int socialCreditsLevel, | ||||||
|     required double levelingProgress, |     required double levelingProgress, | ||||||
|     required SnCloudFile? picture, |     required SnCloudFile? picture, | ||||||
|     required SnCloudFile? background, |     required SnCloudFile? background, | ||||||
| @@ -174,3 +179,70 @@ sealed class SnVerificationMark with _$SnVerificationMark { | |||||||
|   factory SnVerificationMark.fromJson(Map<String, dynamic> json) => |   factory SnVerificationMark.fromJson(Map<String, dynamic> json) => | ||||||
|       _$SnVerificationMarkFromJson(json); |       _$SnVerificationMarkFromJson(json); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @freezed | ||||||
|  | sealed class SnAuthDevice with _$SnAuthDevice { | ||||||
|  |   const factory SnAuthDevice({ | ||||||
|  |     required String id, | ||||||
|  |     required String deviceId, | ||||||
|  |     required String deviceName, | ||||||
|  |     required String? deviceLabel, | ||||||
|  |     required String accountId, | ||||||
|  |     required int platform, | ||||||
|  |     @Default(false) bool isCurrent, | ||||||
|  |   }) = _SnAuthDevice; | ||||||
|  | 
 | ||||||
|  |   factory SnAuthDevice.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$SnAuthDeviceFromJson(json); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @freezed | ||||||
|  | sealed class SnAuthDeviceWithChallenge with _$SnAuthDeviceWithChallenge { | ||||||
|  |   const factory SnAuthDeviceWithChallenge({ | ||||||
|  |     required String id, | ||||||
|  |     required String deviceId, | ||||||
|  |     required String deviceName, | ||||||
|  |     required String? deviceLabel, | ||||||
|  |     required String accountId, | ||||||
|  |     required int platform, | ||||||
|  |     required List<SnAuthChallenge> challenges, | ||||||
|  |     @Default(false) bool isCurrent, | ||||||
|  |   }) = _SnAuthDeviceWithChallengee; | ||||||
|  | 
 | ||||||
|  |   factory SnAuthDeviceWithChallenge.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$SnAuthDeviceWithChallengeFromJson(json); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @freezed | ||||||
|  | sealed class SnExperienceRecord with _$SnExperienceRecord { | ||||||
|  |   const factory SnExperienceRecord({ | ||||||
|  |     required String id, | ||||||
|  |     required int delta, | ||||||
|  |     required String reasonType, | ||||||
|  |     required String reason, | ||||||
|  |     @Default(1.0) double? bonusMultiplier, | ||||||
|  |     required DateTime createdAt, | ||||||
|  |     required DateTime updatedAt, | ||||||
|  |     required DateTime? deletedAt, | ||||||
|  |   }) = _SnExperienceRecord; | ||||||
|  | 
 | ||||||
|  |   factory SnExperienceRecord.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$SnExperienceRecordFromJson(json); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @freezed | ||||||
|  | sealed class SnSocialCreditRecord with _$SnSocialCreditRecord { | ||||||
|  |   const factory SnSocialCreditRecord({ | ||||||
|  |     required String id, | ||||||
|  |     required double delta, | ||||||
|  |     required String reasonType, | ||||||
|  |     required String reason, | ||||||
|  |     required DateTime? expiredAt, | ||||||
|  |     required DateTime createdAt, | ||||||
|  |     required DateTime updatedAt, | ||||||
|  |     required DateTime? deletedAt, | ||||||
|  |   }) = _SnSocialCreditRecord; | ||||||
|  | 
 | ||||||
|  |   factory SnSocialCreditRecord.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$SnSocialCreditRecordFromJson(json); | ||||||
|  | } | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
| 
 | 
 | ||||||
| part of 'user.dart'; | part of 'account.dart'; | ||||||
| 
 | 
 | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
| // JsonSerializableGenerator | // JsonSerializableGenerator | ||||||
| @@ -11,7 +11,9 @@ _SnAccount _$SnAccountFromJson(Map<String, dynamic> json) => _SnAccount( | |||||||
|   name: json['name'] as String, |   name: json['name'] as String, | ||||||
|   nick: json['nick'] as String, |   nick: json['nick'] as String, | ||||||
|   language: json['language'] as String, |   language: json['language'] as String, | ||||||
|  |   region: json['region'] as String? ?? "", | ||||||
|   isSuperuser: json['is_superuser'] as bool, |   isSuperuser: json['is_superuser'] as bool, | ||||||
|  |   automatedId: json['automated_id'] as String?, | ||||||
|   profile: SnAccountProfile.fromJson(json['profile'] as Map<String, dynamic>), |   profile: SnAccountProfile.fromJson(json['profile'] as Map<String, dynamic>), | ||||||
|   perkSubscription: |   perkSubscription: | ||||||
|       json['perk_subscription'] == null |       json['perk_subscription'] == null | ||||||
| @@ -38,7 +40,9 @@ Map<String, dynamic> _$SnAccountToJson(_SnAccount instance) => | |||||||
|       'name': instance.name, |       'name': instance.name, | ||||||
|       'nick': instance.nick, |       'nick': instance.nick, | ||||||
|       'language': instance.language, |       'language': instance.language, | ||||||
|  |       'region': instance.region, | ||||||
|       'is_superuser': instance.isSuperuser, |       'is_superuser': instance.isSuperuser, | ||||||
|  |       'automated_id': instance.automatedId, | ||||||
|       'profile': instance.profile.toJson(), |       'profile': instance.profile.toJson(), | ||||||
|       'perk_subscription': instance.perkSubscription?.toJson(), |       'perk_subscription': instance.perkSubscription?.toJson(), | ||||||
|       'badges': instance.badges.map((e) => e.toJson()).toList(), |       'badges': instance.badges.map((e) => e.toJson()).toList(), | ||||||
| @@ -84,6 +88,8 @@ _SnAccountProfile _$SnAccountProfileFromJson(Map<String, dynamic> json) => | |||||||
|               ), |               ), | ||||||
|       experience: (json['experience'] as num).toInt(), |       experience: (json['experience'] as num).toInt(), | ||||||
|       level: (json['level'] as num).toInt(), |       level: (json['level'] as num).toInt(), | ||||||
|  |       socialCredits: (json['social_credits'] as num?)?.toDouble() ?? 100, | ||||||
|  |       socialCreditsLevel: (json['social_credits_level'] as num?)?.toInt() ?? 0, | ||||||
|       levelingProgress: (json['leveling_progress'] as num).toDouble(), |       levelingProgress: (json['leveling_progress'] as num).toDouble(), | ||||||
|       picture: |       picture: | ||||||
|           json['picture'] == null |           json['picture'] == null | ||||||
| @@ -126,6 +132,8 @@ Map<String, dynamic> _$SnAccountProfileToJson(_SnAccountProfile instance) => | |||||||
|       'active_badge': instance.activeBadge?.toJson(), |       'active_badge': instance.activeBadge?.toJson(), | ||||||
|       'experience': instance.experience, |       'experience': instance.experience, | ||||||
|       'level': instance.level, |       'level': instance.level, | ||||||
|  |       'social_credits': instance.socialCredits, | ||||||
|  |       'social_credits_level': instance.socialCreditsLevel, | ||||||
|       'leveling_progress': instance.levelingProgress, |       'leveling_progress': instance.levelingProgress, | ||||||
|       'picture': instance.picture?.toJson(), |       'picture': instance.picture?.toJson(), | ||||||
|       'background': instance.background?.toJson(), |       'background': instance.background?.toJson(), | ||||||
| @@ -297,3 +305,113 @@ Map<String, dynamic> _$SnVerificationMarkToJson(_SnVerificationMark instance) => | |||||||
|       'description': instance.description, |       'description': instance.description, | ||||||
|       'verified_by': instance.verifiedBy, |       'verified_by': instance.verifiedBy, | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  | _SnAuthDevice _$SnAuthDeviceFromJson(Map<String, dynamic> json) => | ||||||
|  |     _SnAuthDevice( | ||||||
|  |       id: json['id'] as String, | ||||||
|  |       deviceId: json['device_id'] as String, | ||||||
|  |       deviceName: json['device_name'] as String, | ||||||
|  |       deviceLabel: json['device_label'] as String?, | ||||||
|  |       accountId: json['account_id'] as String, | ||||||
|  |       platform: (json['platform'] as num).toInt(), | ||||||
|  |       isCurrent: json['is_current'] as bool? ?? false, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  | Map<String, dynamic> _$SnAuthDeviceToJson(_SnAuthDevice instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'id': instance.id, | ||||||
|  |       'device_id': instance.deviceId, | ||||||
|  |       'device_name': instance.deviceName, | ||||||
|  |       'device_label': instance.deviceLabel, | ||||||
|  |       'account_id': instance.accountId, | ||||||
|  |       'platform': instance.platform, | ||||||
|  |       'is_current': instance.isCurrent, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | _SnAuthDeviceWithChallengee _$SnAuthDeviceWithChallengeeFromJson( | ||||||
|  |   Map<String, dynamic> json, | ||||||
|  | ) => _SnAuthDeviceWithChallengee( | ||||||
|  |   id: json['id'] as String, | ||||||
|  |   deviceId: json['device_id'] as String, | ||||||
|  |   deviceName: json['device_name'] as String, | ||||||
|  |   deviceLabel: json['device_label'] as String?, | ||||||
|  |   accountId: json['account_id'] as String, | ||||||
|  |   platform: (json['platform'] as num).toInt(), | ||||||
|  |   challenges: | ||||||
|  |       (json['challenges'] as List<dynamic>) | ||||||
|  |           .map((e) => SnAuthChallenge.fromJson(e as Map<String, dynamic>)) | ||||||
|  |           .toList(), | ||||||
|  |   isCurrent: json['is_current'] as bool? ?? false, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | Map<String, dynamic> _$SnAuthDeviceWithChallengeeToJson( | ||||||
|  |   _SnAuthDeviceWithChallengee instance, | ||||||
|  | ) => <String, dynamic>{ | ||||||
|  |   'id': instance.id, | ||||||
|  |   'device_id': instance.deviceId, | ||||||
|  |   'device_name': instance.deviceName, | ||||||
|  |   'device_label': instance.deviceLabel, | ||||||
|  |   'account_id': instance.accountId, | ||||||
|  |   'platform': instance.platform, | ||||||
|  |   'challenges': instance.challenges.map((e) => e.toJson()).toList(), | ||||||
|  |   'is_current': instance.isCurrent, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | _SnExperienceRecord _$SnExperienceRecordFromJson(Map<String, dynamic> json) => | ||||||
|  |     _SnExperienceRecord( | ||||||
|  |       id: json['id'] as String, | ||||||
|  |       delta: (json['delta'] as num).toInt(), | ||||||
|  |       reasonType: json['reason_type'] as String, | ||||||
|  |       reason: json['reason'] as String, | ||||||
|  |       bonusMultiplier: (json['bonus_multiplier'] as num?)?.toDouble() ?? 1.0, | ||||||
|  |       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> _$SnExperienceRecordToJson(_SnExperienceRecord instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'id': instance.id, | ||||||
|  |       'delta': instance.delta, | ||||||
|  |       'reason_type': instance.reasonType, | ||||||
|  |       'reason': instance.reason, | ||||||
|  |       'bonus_multiplier': instance.bonusMultiplier, | ||||||
|  |       'created_at': instance.createdAt.toIso8601String(), | ||||||
|  |       'updated_at': instance.updatedAt.toIso8601String(), | ||||||
|  |       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | _SnSocialCreditRecord _$SnSocialCreditRecordFromJson( | ||||||
|  |   Map<String, dynamic> json, | ||||||
|  | ) => _SnSocialCreditRecord( | ||||||
|  |   id: json['id'] as String, | ||||||
|  |   delta: (json['delta'] as num).toDouble(), | ||||||
|  |   reasonType: json['reason_type'] as String, | ||||||
|  |   reason: json['reason'] 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> _$SnSocialCreditRecordToJson( | ||||||
|  |   _SnSocialCreditRecord instance, | ||||||
|  | ) => <String, dynamic>{ | ||||||
|  |   'id': instance.id, | ||||||
|  |   'delta': instance.delta, | ||||||
|  |   'reason_type': instance.reasonType, | ||||||
|  |   'reason': instance.reason, | ||||||
|  |   'expired_at': instance.expiredAt?.toIso8601String(), | ||||||
|  |   'created_at': instance.createdAt.toIso8601String(), | ||||||
|  |   'updated_at': instance.updatedAt.toIso8601String(), | ||||||
|  |   'deleted_at': instance.deletedAt?.toIso8601String(), | ||||||
|  | }; | ||||||
| @@ -1,9 +1,23 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
|  |  | ||||||
| part 'activity.freezed.dart'; | part 'activity.freezed.dart'; | ||||||
| part 'activity.g.dart'; | part 'activity.g.dart'; | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class SnNotableDay with _$SnNotableDay { | ||||||
|  |   const factory SnNotableDay({ | ||||||
|  |     required DateTime date, | ||||||
|  |     required String localName, | ||||||
|  |     required String globalName, | ||||||
|  |     required String countryCode, | ||||||
|  |     required List<int> holidays, | ||||||
|  |   }) = _SnNotableDay; | ||||||
|  |  | ||||||
|  |   factory SnNotableDay.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$SnNotableDayFromJson(json); | ||||||
|  | } | ||||||
|  |  | ||||||
| @freezed | @freezed | ||||||
| sealed class SnActivity with _$SnActivity { | sealed class SnActivity with _$SnActivity { | ||||||
|   const factory SnActivity({ |   const factory SnActivity({ | ||||||
| @@ -54,7 +68,7 @@ sealed class SnEventCalendarEntry with _$SnEventCalendarEntry { | |||||||
|   const factory SnEventCalendarEntry({ |   const factory SnEventCalendarEntry({ | ||||||
|     required DateTime date, |     required DateTime date, | ||||||
|     required SnCheckInResult? checkInResult, |     required SnCheckInResult? checkInResult, | ||||||
|     required List<dynamic> statuses, |     required List<SnAccountStatus> statuses, | ||||||
|   }) = _SnEventCalendarEntry; |   }) = _SnEventCalendarEntry; | ||||||
|  |  | ||||||
|   factory SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => |   factory SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => | ||||||
|   | |||||||
| @@ -12,6 +12,281 @@ part of 'activity.dart'; | |||||||
| // dart format off | // dart format off | ||||||
| T _$identity<T>(T value) => value; | T _$identity<T>(T value) => value; | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | mixin _$SnNotableDay { | ||||||
|  |  | ||||||
|  |  DateTime get date; String get localName; String get globalName; String get countryCode; List<int> get holidays; | ||||||
|  | /// Create a copy of SnNotableDay | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnNotableDayCopyWith<SnNotableDay> get copyWith => _$SnNotableDayCopyWithImpl<SnNotableDay>(this as SnNotableDay, _$identity); | ||||||
|  |  | ||||||
|  |   /// Serializes this SnNotableDay to a JSON map. | ||||||
|  |   Map<String, dynamic> toJson(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnNotableDay&&(identical(other.date, date) || other.date == date)&&(identical(other.localName, localName) || other.localName == localName)&&(identical(other.globalName, globalName) || other.globalName == globalName)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&const DeepCollectionEquality().equals(other.holidays, holidays)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,date,localName,globalName,countryCode,const DeepCollectionEquality().hash(holidays)); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnNotableDay(date: $date, localName: $localName, globalName: $globalName, countryCode: $countryCode, holidays: $holidays)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class $SnNotableDayCopyWith<$Res>  { | ||||||
|  |   factory $SnNotableDayCopyWith(SnNotableDay value, $Res Function(SnNotableDay) _then) = _$SnNotableDayCopyWithImpl; | ||||||
|  | @useResult | ||||||
|  | $Res call({ | ||||||
|  |  DateTime date, String localName, String globalName, String countryCode, List<int> holidays | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class _$SnNotableDayCopyWithImpl<$Res> | ||||||
|  |     implements $SnNotableDayCopyWith<$Res> { | ||||||
|  |   _$SnNotableDayCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final SnNotableDay _self; | ||||||
|  |   final $Res Function(SnNotableDay) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnNotableDay | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @pragma('vm:prefer-inline') @override $Res call({Object? date = null,Object? localName = null,Object? globalName = null,Object? countryCode = null,Object? holidays = null,}) { | ||||||
|  |   return _then(_self.copyWith( | ||||||
|  | date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,localName: null == localName ? _self.localName : localName // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,globalName: null == globalName ? _self.globalName : globalName // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,countryCode: null == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,holidays: null == holidays ? _self.holidays : holidays // ignore: cast_nullable_to_non_nullable | ||||||
|  | as List<int>, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Adds pattern-matching-related methods to [SnNotableDay]. | ||||||
|  | extension SnNotableDayPatterns on SnNotableDay { | ||||||
|  | /// 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( _SnNotableDay value)?  $default,{required TResult orElse(),}){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnNotableDay() 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( _SnNotableDay value)  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnNotableDay(): | ||||||
|  | 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( _SnNotableDay value)?  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnNotableDay() 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( DateTime date,  String localName,  String globalName,  String countryCode,  List<int> holidays)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnNotableDay() when $default != null: | ||||||
|  | return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.holidays);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( DateTime date,  String localName,  String globalName,  String countryCode,  List<int> holidays)  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnNotableDay(): | ||||||
|  | return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.holidays);} | ||||||
|  | } | ||||||
|  | /// 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( DateTime date,  String localName,  String globalName,  String countryCode,  List<int> holidays)?  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnNotableDay() when $default != null: | ||||||
|  | return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.holidays);case _: | ||||||
|  |   return null; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | @JsonSerializable() | ||||||
|  |  | ||||||
|  | class _SnNotableDay implements SnNotableDay { | ||||||
|  |   const _SnNotableDay({required this.date, required this.localName, required this.globalName, required this.countryCode, required final  List<int> holidays}): _holidays = holidays; | ||||||
|  |   factory _SnNotableDay.fromJson(Map<String, dynamic> json) => _$SnNotableDayFromJson(json); | ||||||
|  |  | ||||||
|  | @override final  DateTime date; | ||||||
|  | @override final  String localName; | ||||||
|  | @override final  String globalName; | ||||||
|  | @override final  String countryCode; | ||||||
|  |  final  List<int> _holidays; | ||||||
|  | @override List<int> get holidays { | ||||||
|  |   if (_holidays is EqualUnmodifiableListView) return _holidays; | ||||||
|  |   // ignore: implicit_dynamic_type | ||||||
|  |   return EqualUnmodifiableListView(_holidays); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Create a copy of SnNotableDay | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | _$SnNotableDayCopyWith<_SnNotableDay> get copyWith => __$SnNotableDayCopyWithImpl<_SnNotableDay>(this, _$identity); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | Map<String, dynamic> toJson() { | ||||||
|  |   return _$SnNotableDayToJson(this, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnNotableDay&&(identical(other.date, date) || other.date == date)&&(identical(other.localName, localName) || other.localName == localName)&&(identical(other.globalName, globalName) || other.globalName == globalName)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&const DeepCollectionEquality().equals(other._holidays, _holidays)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,date,localName,globalName,countryCode,const DeepCollectionEquality().hash(_holidays)); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnNotableDay(date: $date, localName: $localName, globalName: $globalName, countryCode: $countryCode, holidays: $holidays)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class _$SnNotableDayCopyWith<$Res> implements $SnNotableDayCopyWith<$Res> { | ||||||
|  |   factory _$SnNotableDayCopyWith(_SnNotableDay value, $Res Function(_SnNotableDay) _then) = __$SnNotableDayCopyWithImpl; | ||||||
|  | @override @useResult | ||||||
|  | $Res call({ | ||||||
|  |  DateTime date, String localName, String globalName, String countryCode, List<int> holidays | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class __$SnNotableDayCopyWithImpl<$Res> | ||||||
|  |     implements _$SnNotableDayCopyWith<$Res> { | ||||||
|  |   __$SnNotableDayCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final _SnNotableDay _self; | ||||||
|  |   final $Res Function(_SnNotableDay) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnNotableDay | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @pragma('vm:prefer-inline') $Res call({Object? date = null,Object? localName = null,Object? globalName = null,Object? countryCode = null,Object? holidays = null,}) { | ||||||
|  |   return _then(_SnNotableDay( | ||||||
|  | date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,localName: null == localName ? _self.localName : localName // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,globalName: null == globalName ? _self.globalName : globalName // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,countryCode: null == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,holidays: null == holidays ? _self._holidays : holidays // ignore: cast_nullable_to_non_nullable | ||||||
|  | as List<int>, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnActivity { | mixin _$SnActivity { | ||||||
|  |  | ||||||
| @@ -861,7 +1136,7 @@ as String, | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnEventCalendarEntry { | mixin _$SnEventCalendarEntry { | ||||||
|  |  | ||||||
|  DateTime get date; SnCheckInResult? get checkInResult; List<dynamic> get statuses; |  DateTime get date; SnCheckInResult? get checkInResult; List<SnAccountStatus> get statuses; | ||||||
| /// Create a copy of SnEventCalendarEntry | /// Create a copy of SnEventCalendarEntry | ||||||
| /// 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) | ||||||
| @@ -894,7 +1169,7 @@ abstract mixin class $SnEventCalendarEntryCopyWith<$Res>  { | |||||||
|   factory $SnEventCalendarEntryCopyWith(SnEventCalendarEntry value, $Res Function(SnEventCalendarEntry) _then) = _$SnEventCalendarEntryCopyWithImpl; |   factory $SnEventCalendarEntryCopyWith(SnEventCalendarEntry value, $Res Function(SnEventCalendarEntry) _then) = _$SnEventCalendarEntryCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses |  DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -916,7 +1191,7 @@ class _$SnEventCalendarEntryCopyWithImpl<$Res> | |||||||
| date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCheckInResult?,statuses: null == statuses ? _self.statuses : statuses // ignore: cast_nullable_to_non_nullable | as SnCheckInResult?,statuses: null == statuses ? _self.statuses : statuses // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>, | as List<SnAccountStatus>, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
| /// Create a copy of SnEventCalendarEntry | /// Create a copy of SnEventCalendarEntry | ||||||
| @@ -1010,7 +1285,7 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnEventCalendarEntry() when $default != null: | case _SnEventCalendarEntry() when $default != null: | ||||||
| return $default(_that.date,_that.checkInResult,_that.statuses);case _: | return $default(_that.date,_that.checkInResult,_that.statuses);case _: | ||||||
| @@ -1031,7 +1306,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnEventCalendarEntry(): | case _SnEventCalendarEntry(): | ||||||
| return $default(_that.date,_that.checkInResult,_that.statuses);} | return $default(_that.date,_that.checkInResult,_that.statuses);} | ||||||
| @@ -1048,7 +1323,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);} | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnEventCalendarEntry() when $default != null: | case _SnEventCalendarEntry() when $default != null: | ||||||
| return $default(_that.date,_that.checkInResult,_that.statuses);case _: | return $default(_that.date,_that.checkInResult,_that.statuses);case _: | ||||||
| @@ -1063,13 +1338,13 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _: | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnEventCalendarEntry implements SnEventCalendarEntry { | class _SnEventCalendarEntry implements SnEventCalendarEntry { | ||||||
|   const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final  List<dynamic> statuses}): _statuses = statuses; |   const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final  List<SnAccountStatus> statuses}): _statuses = statuses; | ||||||
|   factory _SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => _$SnEventCalendarEntryFromJson(json); |   factory _SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => _$SnEventCalendarEntryFromJson(json); | ||||||
|  |  | ||||||
| @override final  DateTime date; | @override final  DateTime date; | ||||||
| @override final  SnCheckInResult? checkInResult; | @override final  SnCheckInResult? checkInResult; | ||||||
|  final  List<dynamic> _statuses; |  final  List<SnAccountStatus> _statuses; | ||||||
| @override List<dynamic> get statuses { | @override List<SnAccountStatus> get statuses { | ||||||
|   if (_statuses is EqualUnmodifiableListView) return _statuses; |   if (_statuses is EqualUnmodifiableListView) return _statuses; | ||||||
|   // ignore: implicit_dynamic_type |   // ignore: implicit_dynamic_type | ||||||
|   return EqualUnmodifiableListView(_statuses); |   return EqualUnmodifiableListView(_statuses); | ||||||
| @@ -1109,7 +1384,7 @@ abstract mixin class _$SnEventCalendarEntryCopyWith<$Res> implements $SnEventCal | |||||||
|   factory _$SnEventCalendarEntryCopyWith(_SnEventCalendarEntry value, $Res Function(_SnEventCalendarEntry) _then) = __$SnEventCalendarEntryCopyWithImpl; |   factory _$SnEventCalendarEntryCopyWith(_SnEventCalendarEntry value, $Res Function(_SnEventCalendarEntry) _then) = __$SnEventCalendarEntryCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses |  DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1131,7 +1406,7 @@ class __$SnEventCalendarEntryCopyWithImpl<$Res> | |||||||
| date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCheckInResult?,statuses: null == statuses ? _self._statuses : statuses // ignore: cast_nullable_to_non_nullable | as SnCheckInResult?,statuses: null == statuses ? _self._statuses : statuses // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>, | as List<SnAccountStatus>, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,27 @@ part of 'activity.dart'; | |||||||
| // JsonSerializableGenerator | // JsonSerializableGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
|  | _SnNotableDay _$SnNotableDayFromJson(Map<String, dynamic> json) => | ||||||
|  |     _SnNotableDay( | ||||||
|  |       date: DateTime.parse(json['date'] as String), | ||||||
|  |       localName: json['local_name'] as String, | ||||||
|  |       globalName: json['global_name'] as String, | ||||||
|  |       countryCode: json['country_code'] as String, | ||||||
|  |       holidays: | ||||||
|  |           (json['holidays'] as List<dynamic>) | ||||||
|  |               .map((e) => (e as num).toInt()) | ||||||
|  |               .toList(), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$SnNotableDayToJson(_SnNotableDay instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'date': instance.date.toIso8601String(), | ||||||
|  |       'local_name': instance.localName, | ||||||
|  |       'global_name': instance.globalName, | ||||||
|  |       'country_code': instance.countryCode, | ||||||
|  |       'holidays': instance.holidays, | ||||||
|  |     }; | ||||||
|  |  | ||||||
| _SnActivity _$SnActivityFromJson(Map<String, dynamic> json) => _SnActivity( | _SnActivity _$SnActivityFromJson(Map<String, dynamic> json) => _SnActivity( | ||||||
|   id: json['id'] as String, |   id: json['id'] as String, | ||||||
|   type: json['type'] as String, |   type: json['type'] as String, | ||||||
| @@ -87,7 +108,10 @@ _SnEventCalendarEntry _$SnEventCalendarEntryFromJson( | |||||||
|           : SnCheckInResult.fromJson( |           : SnCheckInResult.fromJson( | ||||||
|             json['check_in_result'] as Map<String, dynamic>, |             json['check_in_result'] as Map<String, dynamic>, | ||||||
|           ), |           ), | ||||||
|   statuses: json['statuses'] as List<dynamic>, |   statuses: | ||||||
|  |       (json['statuses'] as List<dynamic>) | ||||||
|  |           .map((e) => SnAccountStatus.fromJson(e as Map<String, dynamic>)) | ||||||
|  |           .toList(), | ||||||
| ); | ); | ||||||
|  |  | ||||||
| Map<String, dynamic> _$SnEventCalendarEntryToJson( | Map<String, dynamic> _$SnEventCalendarEntryToJson( | ||||||
| @@ -95,5 +119,5 @@ Map<String, dynamic> _$SnEventCalendarEntryToJson( | |||||||
| ) => <String, dynamic>{ | ) => <String, dynamic>{ | ||||||
|   'date': instance.date.toIso8601String(), |   'date': instance.date.toIso8601String(), | ||||||
|   'check_in_result': instance.checkInResult?.toJson(), |   'check_in_result': instance.checkInResult?.toJson(), | ||||||
|   'statuses': instance.statuses, |   'statuses': instance.statuses.map((e) => e.toJson()).toList(), | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -11,6 +11,20 @@ sealed class AppToken with _$AppToken { | |||||||
|       _$AppTokenFromJson(json); |       _$AppTokenFromJson(json); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class GeoIpLocation with _$GeoIpLocation { | ||||||
|  |   const factory GeoIpLocation({ | ||||||
|  |     required double latitude, | ||||||
|  |     required double longitude, | ||||||
|  |     required String countryCode, | ||||||
|  |     required String country, | ||||||
|  |     required String city, | ||||||
|  |   }) = _GeoIpLocation; | ||||||
|  |  | ||||||
|  |   factory GeoIpLocation.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$GeoIpLocationFromJson(json); | ||||||
|  | } | ||||||
|  |  | ||||||
| @freezed | @freezed | ||||||
| sealed class SnAuthChallenge with _$SnAuthChallenge { | sealed class SnAuthChallenge with _$SnAuthChallenge { | ||||||
|   const factory SnAuthChallenge({ |   const factory SnAuthChallenge({ | ||||||
| @@ -19,16 +33,14 @@ sealed class SnAuthChallenge with _$SnAuthChallenge { | |||||||
|     required int stepRemain, |     required int stepRemain, | ||||||
|     required int stepTotal, |     required int stepTotal, | ||||||
|     required int failedAttempts, |     required int failedAttempts, | ||||||
|     required int platform, |  | ||||||
|     required int type, |     required int type, | ||||||
|     required List<String> blacklistFactors, |     required List<String> blacklistFactors, | ||||||
|     required List<dynamic> audiences, |     required List<dynamic> audiences, | ||||||
|     required List<dynamic> scopes, |     required List<dynamic> scopes, | ||||||
|     required String ipAddress, |     required String ipAddress, | ||||||
|     required String userAgent, |     required String userAgent, | ||||||
|     required String deviceId, |  | ||||||
|     required String? nonce, |     required String? nonce, | ||||||
|     required String? location, |     required GeoIpLocation? location, | ||||||
|     required String accountId, |     required String accountId, | ||||||
|     required DateTime createdAt, |     required DateTime createdAt, | ||||||
|     required DateTime updatedAt, |     required DateTime updatedAt, | ||||||
| @@ -76,22 +88,6 @@ sealed class SnAuthFactor with _$SnAuthFactor { | |||||||
|       _$SnAuthFactorFromJson(json); |       _$SnAuthFactorFromJson(json); | ||||||
| } | } | ||||||
|  |  | ||||||
| @freezed |  | ||||||
| sealed class SnAuthDevice with _$SnAuthDevice { |  | ||||||
|   const factory SnAuthDevice({ |  | ||||||
|     required dynamic label, |  | ||||||
|     required String userAgent, |  | ||||||
|     required String deviceId, |  | ||||||
|     required int platform, |  | ||||||
|     required List<SnAuthSession> sessions, |  | ||||||
|     // Not from backend, used for UI |  | ||||||
|     @Default(false) bool isCurrent, |  | ||||||
|   }) = _SnAuthDevice; |  | ||||||
|  |  | ||||||
|   factory SnAuthDevice.fromJson(Map<String, dynamic> json) => |  | ||||||
|       _$SnAuthDeviceFromJson(json); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @freezed | @freezed | ||||||
| sealed class SnAccountConnection with _$SnAccountConnection { | sealed class SnAccountConnection with _$SnAccountConnection { | ||||||
|   const factory SnAccountConnection({ |   const factory SnAccountConnection({ | ||||||
|   | |||||||
| @@ -269,10 +269,279 @@ as String, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | mixin _$GeoIpLocation { | ||||||
|  |  | ||||||
|  |  double get latitude; double get longitude; String get countryCode; String get country; String get city; | ||||||
|  | /// Create a copy of GeoIpLocation | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $GeoIpLocationCopyWith<GeoIpLocation> get copyWith => _$GeoIpLocationCopyWithImpl<GeoIpLocation>(this as GeoIpLocation, _$identity); | ||||||
|  |  | ||||||
|  |   /// Serializes this GeoIpLocation to a JSON map. | ||||||
|  |   Map<String, dynamic> toJson(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is GeoIpLocation&&(identical(other.latitude, latitude) || other.latitude == latitude)&&(identical(other.longitude, longitude) || other.longitude == longitude)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&(identical(other.country, country) || other.country == country)&&(identical(other.city, city) || other.city == city)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,latitude,longitude,countryCode,country,city); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'GeoIpLocation(latitude: $latitude, longitude: $longitude, countryCode: $countryCode, country: $country, city: $city)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class $GeoIpLocationCopyWith<$Res>  { | ||||||
|  |   factory $GeoIpLocationCopyWith(GeoIpLocation value, $Res Function(GeoIpLocation) _then) = _$GeoIpLocationCopyWithImpl; | ||||||
|  | @useResult | ||||||
|  | $Res call({ | ||||||
|  |  double latitude, double longitude, String countryCode, String country, String city | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class _$GeoIpLocationCopyWithImpl<$Res> | ||||||
|  |     implements $GeoIpLocationCopyWith<$Res> { | ||||||
|  |   _$GeoIpLocationCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final GeoIpLocation _self; | ||||||
|  |   final $Res Function(GeoIpLocation) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of GeoIpLocation | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @pragma('vm:prefer-inline') @override $Res call({Object? latitude = null,Object? longitude = null,Object? countryCode = null,Object? country = null,Object? city = null,}) { | ||||||
|  |   return _then(_self.copyWith( | ||||||
|  | latitude: null == latitude ? _self.latitude : latitude // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,longitude: null == longitude ? _self.longitude : longitude // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,countryCode: null == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,country: null == country ? _self.country : country // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,city: null == city ? _self.city : city // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Adds pattern-matching-related methods to [GeoIpLocation]. | ||||||
|  | extension GeoIpLocationPatterns on GeoIpLocation { | ||||||
|  | /// 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( _GeoIpLocation value)?  $default,{required TResult orElse(),}){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _GeoIpLocation() 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( _GeoIpLocation value)  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _GeoIpLocation(): | ||||||
|  | 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( _GeoIpLocation value)?  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _GeoIpLocation() 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( double latitude,  double longitude,  String countryCode,  String country,  String city)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _GeoIpLocation() when $default != null: | ||||||
|  | return $default(_that.latitude,_that.longitude,_that.countryCode,_that.country,_that.city);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( double latitude,  double longitude,  String countryCode,  String country,  String city)  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _GeoIpLocation(): | ||||||
|  | return $default(_that.latitude,_that.longitude,_that.countryCode,_that.country,_that.city);} | ||||||
|  | } | ||||||
|  | /// 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( double latitude,  double longitude,  String countryCode,  String country,  String city)?  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _GeoIpLocation() when $default != null: | ||||||
|  | return $default(_that.latitude,_that.longitude,_that.countryCode,_that.country,_that.city);case _: | ||||||
|  |   return null; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | @JsonSerializable() | ||||||
|  |  | ||||||
|  | class _GeoIpLocation implements GeoIpLocation { | ||||||
|  |   const _GeoIpLocation({required this.latitude, required this.longitude, required this.countryCode, required this.country, required this.city}); | ||||||
|  |   factory _GeoIpLocation.fromJson(Map<String, dynamic> json) => _$GeoIpLocationFromJson(json); | ||||||
|  |  | ||||||
|  | @override final  double latitude; | ||||||
|  | @override final  double longitude; | ||||||
|  | @override final  String countryCode; | ||||||
|  | @override final  String country; | ||||||
|  | @override final  String city; | ||||||
|  |  | ||||||
|  | /// Create a copy of GeoIpLocation | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | _$GeoIpLocationCopyWith<_GeoIpLocation> get copyWith => __$GeoIpLocationCopyWithImpl<_GeoIpLocation>(this, _$identity); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | Map<String, dynamic> toJson() { | ||||||
|  |   return _$GeoIpLocationToJson(this, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _GeoIpLocation&&(identical(other.latitude, latitude) || other.latitude == latitude)&&(identical(other.longitude, longitude) || other.longitude == longitude)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&(identical(other.country, country) || other.country == country)&&(identical(other.city, city) || other.city == city)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,latitude,longitude,countryCode,country,city); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'GeoIpLocation(latitude: $latitude, longitude: $longitude, countryCode: $countryCode, country: $country, city: $city)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class _$GeoIpLocationCopyWith<$Res> implements $GeoIpLocationCopyWith<$Res> { | ||||||
|  |   factory _$GeoIpLocationCopyWith(_GeoIpLocation value, $Res Function(_GeoIpLocation) _then) = __$GeoIpLocationCopyWithImpl; | ||||||
|  | @override @useResult | ||||||
|  | $Res call({ | ||||||
|  |  double latitude, double longitude, String countryCode, String country, String city | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class __$GeoIpLocationCopyWithImpl<$Res> | ||||||
|  |     implements _$GeoIpLocationCopyWith<$Res> { | ||||||
|  |   __$GeoIpLocationCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final _GeoIpLocation _self; | ||||||
|  |   final $Res Function(_GeoIpLocation) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of GeoIpLocation | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @pragma('vm:prefer-inline') $Res call({Object? latitude = null,Object? longitude = null,Object? countryCode = null,Object? country = null,Object? city = null,}) { | ||||||
|  |   return _then(_GeoIpLocation( | ||||||
|  | latitude: null == latitude ? _self.latitude : latitude // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,longitude: null == longitude ? _self.longitude : longitude // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,countryCode: null == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,country: null == country ? _self.country : country // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,city: null == city ? _self.city : city // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnAuthChallenge { | mixin _$SnAuthChallenge { | ||||||
|  |  | ||||||
|  String get id; DateTime get expiredAt; int get stepRemain; int get stepTotal; int get failedAttempts; int get platform; int get type; List<String> get blacklistFactors; List<dynamic> get audiences; List<dynamic> get scopes; String get ipAddress; String get userAgent; String get deviceId; String? get nonce; String? get location; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; |  String get id; DateTime get expiredAt; int get stepRemain; int get stepTotal; int get failedAttempts; int get type; List<String> get blacklistFactors; List<dynamic> get audiences; List<dynamic> get scopes; String get ipAddress; String get userAgent; String? get nonce; GeoIpLocation? get location; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
| /// Create a copy of SnAuthChallenge | /// Create a copy of SnAuthChallenge | ||||||
| /// 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) | ||||||
| @@ -285,16 +554,16 @@ $SnAuthChallengeCopyWith<SnAuthChallenge> get copyWith => _$SnAuthChallengeCopyW | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.blacklistFactors, blacklistFactors)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.blacklistFactors, blacklistFactors)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hashAll([runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,platform,type,const DeepCollectionEquality().hash(blacklistFactors),const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,deviceId,nonce,location,accountId,createdAt,updatedAt,deletedAt]); | int get hashCode => Object.hash(runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,type,const DeepCollectionEquality().hash(blacklistFactors),const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,nonce,location,accountId,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, platform: $platform, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -305,11 +574,11 @@ abstract mixin class $SnAuthChallengeCopyWith<$Res>  { | |||||||
|   factory $SnAuthChallengeCopyWith(SnAuthChallenge value, $Res Function(SnAuthChallenge) _then) = _$SnAuthChallengeCopyWithImpl; |   factory $SnAuthChallengeCopyWith(SnAuthChallenge value, $Res Function(SnAuthChallenge) _then) = _$SnAuthChallengeCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String? nonce, GeoIpLocation? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | $GeoIpLocationCopyWith<$Res>? get location; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -322,31 +591,41 @@ class _$SnAuthChallengeCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAuthChallenge | /// Create a copy of SnAuthChallenge | ||||||
| /// 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? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? platform = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,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,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable | as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable | ||||||
| as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable | as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable | ||||||
| as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable | as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable | ||||||
| as int,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable |  | ||||||
| as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||||
| as int,blacklistFactors: null == blacklistFactors ? _self.blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable | as int,blacklistFactors: null == blacklistFactors ? _self.blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable | ||||||
| as List<String>,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable | as List<String>,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable | as List<dynamic>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable | as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable | ||||||
| as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable | as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable | ||||||
| as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable |  | ||||||
| as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable | as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable | as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | as GeoIpLocation?,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,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?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  | /// Create a copy of SnAuthChallenge | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $GeoIpLocationCopyWith<$Res>? get location { | ||||||
|  |     if (_self.location == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $GeoIpLocationCopyWith<$Res>(_self.location!, (value) { | ||||||
|  |     return _then(_self.copyWith(location: value)); | ||||||
|  |   }); | ||||||
|  | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -425,10 +704,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  DateTime expiredAt,  int stepRemain,  int stepTotal,  int failedAttempts,  int platform,  int type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  String deviceId,  String? nonce,  String? location,  String accountId,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  DateTime expiredAt,  int stepRemain,  int stepTotal,  int failedAttempts,  int type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  String? nonce,  GeoIpLocation? location,  String accountId,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAuthChallenge() when $default != null: | case _SnAuthChallenge() when $default != null: | ||||||
| return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.platform,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.deviceId,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -446,10 +725,10 @@ return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that. | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  DateTime expiredAt,  int stepRemain,  int stepTotal,  int failedAttempts,  int platform,  int type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  String deviceId,  String? nonce,  String? location,  String accountId,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  DateTime expiredAt,  int stepRemain,  int stepTotal,  int failedAttempts,  int type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  String? nonce,  GeoIpLocation? location,  String accountId,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAuthChallenge(): | case _SnAuthChallenge(): | ||||||
| return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.platform,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.deviceId,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} | return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -463,10 +742,10 @@ return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that. | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  DateTime expiredAt,  int stepRemain,  int stepTotal,  int failedAttempts,  int platform,  int type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  String deviceId,  String? nonce,  String? location,  String accountId,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  DateTime expiredAt,  int stepRemain,  int stepTotal,  int failedAttempts,  int type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  String? nonce,  GeoIpLocation? location,  String accountId,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAuthChallenge() when $default != null: | case _SnAuthChallenge() when $default != null: | ||||||
| return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.platform,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.deviceId,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -478,7 +757,7 @@ return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that. | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnAuthChallenge implements SnAuthChallenge { | class _SnAuthChallenge implements SnAuthChallenge { | ||||||
|   const _SnAuthChallenge({required this.id, required this.expiredAt, required this.stepRemain, required this.stepTotal, required this.failedAttempts, required this.platform, required this.type, required final  List<String> blacklistFactors, required final  List<dynamic> audiences, required final  List<dynamic> scopes, required this.ipAddress, required this.userAgent, required this.deviceId, required this.nonce, required this.location, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _blacklistFactors = blacklistFactors,_audiences = audiences,_scopes = scopes; |   const _SnAuthChallenge({required this.id, required this.expiredAt, required this.stepRemain, required this.stepTotal, required this.failedAttempts, required this.type, required final  List<String> blacklistFactors, required final  List<dynamic> audiences, required final  List<dynamic> scopes, required this.ipAddress, required this.userAgent, required this.nonce, required this.location, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _blacklistFactors = blacklistFactors,_audiences = audiences,_scopes = scopes; | ||||||
|   factory _SnAuthChallenge.fromJson(Map<String, dynamic> json) => _$SnAuthChallengeFromJson(json); |   factory _SnAuthChallenge.fromJson(Map<String, dynamic> json) => _$SnAuthChallengeFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @@ -486,7 +765,6 @@ class _SnAuthChallenge implements SnAuthChallenge { | |||||||
| @override final  int stepRemain; | @override final  int stepRemain; | ||||||
| @override final  int stepTotal; | @override final  int stepTotal; | ||||||
| @override final  int failedAttempts; | @override final  int failedAttempts; | ||||||
| @override final  int platform; |  | ||||||
| @override final  int type; | @override final  int type; | ||||||
|  final  List<String> _blacklistFactors; |  final  List<String> _blacklistFactors; | ||||||
| @override List<String> get blacklistFactors { | @override List<String> get blacklistFactors { | ||||||
| @@ -511,9 +789,8 @@ class _SnAuthChallenge implements SnAuthChallenge { | |||||||
|  |  | ||||||
| @override final  String ipAddress; | @override final  String ipAddress; | ||||||
| @override final  String userAgent; | @override final  String userAgent; | ||||||
| @override final  String deviceId; |  | ||||||
| @override final  String? nonce; | @override final  String? nonce; | ||||||
| @override final  String? location; | @override final  GeoIpLocation? location; | ||||||
| @override final  String accountId; | @override final  String accountId; | ||||||
| @override final  DateTime createdAt; | @override final  DateTime createdAt; | ||||||
| @override final  DateTime updatedAt; | @override final  DateTime updatedAt; | ||||||
| @@ -532,16 +809,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._blacklistFactors, _blacklistFactors)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._blacklistFactors, _blacklistFactors)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hashAll([runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,platform,type,const DeepCollectionEquality().hash(_blacklistFactors),const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,deviceId,nonce,location,accountId,createdAt,updatedAt,deletedAt]); | int get hashCode => Object.hash(runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,type,const DeepCollectionEquality().hash(_blacklistFactors),const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,nonce,location,accountId,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, platform: $platform, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -552,11 +829,11 @@ abstract mixin class _$SnAuthChallengeCopyWith<$Res> implements $SnAuthChallenge | |||||||
|   factory _$SnAuthChallengeCopyWith(_SnAuthChallenge value, $Res Function(_SnAuthChallenge) _then) = __$SnAuthChallengeCopyWithImpl; |   factory _$SnAuthChallengeCopyWith(_SnAuthChallenge value, $Res Function(_SnAuthChallenge) _then) = __$SnAuthChallengeCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String? nonce, GeoIpLocation? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override $GeoIpLocationCopyWith<$Res>? get location; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -569,24 +846,22 @@ class __$SnAuthChallengeCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAuthChallenge | /// Create a copy of SnAuthChallenge | ||||||
| /// 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? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? platform = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|   return _then(_SnAuthChallenge( |   return _then(_SnAuthChallenge( | ||||||
| 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,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable | as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable | ||||||
| as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable | as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable | ||||||
| as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable | as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable | ||||||
| as int,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable |  | ||||||
| as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||||
| as int,blacklistFactors: null == blacklistFactors ? _self._blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable | as int,blacklistFactors: null == blacklistFactors ? _self._blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable | ||||||
| as List<String>,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable | as List<String>,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable | as List<dynamic>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable | ||||||
| as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable | as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable | ||||||
| as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable | as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable | ||||||
| as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable |  | ||||||
| as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable | as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable | as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | as GeoIpLocation?,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,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 | ||||||
| @@ -594,7 +869,19 @@ as DateTime?, | |||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Create a copy of SnAuthChallenge | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $GeoIpLocationCopyWith<$Res>? get location { | ||||||
|  |     if (_self.location == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $GeoIpLocationCopyWith<$Res>(_self.location!, (value) { | ||||||
|  |     return _then(_self.copyWith(location: value)); | ||||||
|  |   }); | ||||||
|  | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1189,286 +1476,6 @@ as Map<String, dynamic>?, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// @nodoc |  | ||||||
| mixin _$SnAuthDevice { |  | ||||||
|  |  | ||||||
|  dynamic get label; String get userAgent; String get deviceId; int get platform; List<SnAuthSession> get sessions;// Not from backend, used for UI |  | ||||||
|  bool get isCurrent; |  | ||||||
| /// Create a copy of SnAuthDevice |  | ||||||
| /// with the given fields replaced by the non-null parameter values. |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) |  | ||||||
| @pragma('vm:prefer-inline') |  | ||||||
| $SnAuthDeviceCopyWith<SnAuthDevice> get copyWith => _$SnAuthDeviceCopyWithImpl<SnAuthDevice>(this as SnAuthDevice, _$identity); |  | ||||||
|  |  | ||||||
|   /// Serializes this SnAuthDevice to a JSON map. |  | ||||||
|   Map<String, dynamic> toJson(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @override |  | ||||||
| bool operator ==(Object other) { |  | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDevice&&const DeepCollectionEquality().equals(other.label, label)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other.sessions, sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) |  | ||||||
| @override |  | ||||||
| int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(label),userAgent,deviceId,platform,const DeepCollectionEquality().hash(sessions),isCurrent); |  | ||||||
|  |  | ||||||
| @override |  | ||||||
| String toString() { |  | ||||||
|   return 'SnAuthDevice(label: $label, userAgent: $userAgent, deviceId: $deviceId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// @nodoc |  | ||||||
| abstract mixin class $SnAuthDeviceCopyWith<$Res>  { |  | ||||||
|   factory $SnAuthDeviceCopyWith(SnAuthDevice value, $Res Function(SnAuthDevice) _then) = _$SnAuthDeviceCopyWithImpl; |  | ||||||
| @useResult |  | ||||||
| $Res call({ |  | ||||||
|  dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent |  | ||||||
| }); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
| /// @nodoc |  | ||||||
| class _$SnAuthDeviceCopyWithImpl<$Res> |  | ||||||
|     implements $SnAuthDeviceCopyWith<$Res> { |  | ||||||
|   _$SnAuthDeviceCopyWithImpl(this._self, this._then); |  | ||||||
|  |  | ||||||
|   final SnAuthDevice _self; |  | ||||||
|   final $Res Function(SnAuthDevice) _then; |  | ||||||
|  |  | ||||||
| /// Create a copy of SnAuthDevice |  | ||||||
| /// with the given fields replaced by the non-null parameter values. |  | ||||||
| @pragma('vm:prefer-inline') @override $Res call({Object? label = freezed,Object? userAgent = null,Object? deviceId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) { |  | ||||||
|   return _then(_self.copyWith( |  | ||||||
| label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable |  | ||||||
| as dynamic,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable |  | ||||||
| as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable |  | ||||||
| as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable |  | ||||||
| as int,sessions: null == sessions ? _self.sessions : sessions // ignore: cast_nullable_to_non_nullable |  | ||||||
| as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable |  | ||||||
| as bool, |  | ||||||
|   )); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Adds pattern-matching-related methods to [SnAuthDevice]. |  | ||||||
| extension SnAuthDevicePatterns on SnAuthDevice { |  | ||||||
| /// 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( _SnAuthDevice value)?  $default,{required TResult orElse(),}){ |  | ||||||
| final _that = this; |  | ||||||
| switch (_that) { |  | ||||||
| case _SnAuthDevice() 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( _SnAuthDevice value)  $default,){ |  | ||||||
| final _that = this; |  | ||||||
| switch (_that) { |  | ||||||
| case _SnAuthDevice(): |  | ||||||
| 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( _SnAuthDevice value)?  $default,){ |  | ||||||
| final _that = this; |  | ||||||
| switch (_that) { |  | ||||||
| case _SnAuthDevice() 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( dynamic label,  String userAgent,  String deviceId,  int platform,  List<SnAuthSession> sessions,  bool isCurrent)?  $default,{required TResult orElse(),}) {final _that = this; |  | ||||||
| switch (_that) { |  | ||||||
| case _SnAuthDevice() when $default != null: |  | ||||||
| return $default(_that.label,_that.userAgent,_that.deviceId,_that.platform,_that.sessions,_that.isCurrent);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( dynamic label,  String userAgent,  String deviceId,  int platform,  List<SnAuthSession> sessions,  bool isCurrent)  $default,) {final _that = this; |  | ||||||
| switch (_that) { |  | ||||||
| case _SnAuthDevice(): |  | ||||||
| return $default(_that.label,_that.userAgent,_that.deviceId,_that.platform,_that.sessions,_that.isCurrent);} |  | ||||||
| } |  | ||||||
| /// 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( dynamic label,  String userAgent,  String deviceId,  int platform,  List<SnAuthSession> sessions,  bool isCurrent)?  $default,) {final _that = this; |  | ||||||
| switch (_that) { |  | ||||||
| case _SnAuthDevice() when $default != null: |  | ||||||
| return $default(_that.label,_that.userAgent,_that.deviceId,_that.platform,_that.sessions,_that.isCurrent);case _: |  | ||||||
|   return null; |  | ||||||
|  |  | ||||||
| } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// @nodoc |  | ||||||
| @JsonSerializable() |  | ||||||
|  |  | ||||||
| class _SnAuthDevice implements SnAuthDevice { |  | ||||||
|   const _SnAuthDevice({required this.label, required this.userAgent, required this.deviceId, required this.platform, required final  List<SnAuthSession> sessions, this.isCurrent = false}): _sessions = sessions; |  | ||||||
|   factory _SnAuthDevice.fromJson(Map<String, dynamic> json) => _$SnAuthDeviceFromJson(json); |  | ||||||
|  |  | ||||||
| @override final  dynamic label; |  | ||||||
| @override final  String userAgent; |  | ||||||
| @override final  String deviceId; |  | ||||||
| @override final  int platform; |  | ||||||
|  final  List<SnAuthSession> _sessions; |  | ||||||
| @override List<SnAuthSession> get sessions { |  | ||||||
|   if (_sessions is EqualUnmodifiableListView) return _sessions; |  | ||||||
|   // ignore: implicit_dynamic_type |  | ||||||
|   return EqualUnmodifiableListView(_sessions); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Not from backend, used for UI |  | ||||||
| @override@JsonKey() final  bool isCurrent; |  | ||||||
|  |  | ||||||
| /// Create a copy of SnAuthDevice |  | ||||||
| /// with the given fields replaced by the non-null parameter values. |  | ||||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) |  | ||||||
| @pragma('vm:prefer-inline') |  | ||||||
| _$SnAuthDeviceCopyWith<_SnAuthDevice> get copyWith => __$SnAuthDeviceCopyWithImpl<_SnAuthDevice>(this, _$identity); |  | ||||||
|  |  | ||||||
| @override |  | ||||||
| Map<String, dynamic> toJson() { |  | ||||||
|   return _$SnAuthDeviceToJson(this, ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @override |  | ||||||
| bool operator ==(Object other) { |  | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDevice&&const DeepCollectionEquality().equals(other.label, label)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other._sessions, _sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) |  | ||||||
| @override |  | ||||||
| int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(label),userAgent,deviceId,platform,const DeepCollectionEquality().hash(_sessions),isCurrent); |  | ||||||
|  |  | ||||||
| @override |  | ||||||
| String toString() { |  | ||||||
|   return 'SnAuthDevice(label: $label, userAgent: $userAgent, deviceId: $deviceId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// @nodoc |  | ||||||
| abstract mixin class _$SnAuthDeviceCopyWith<$Res> implements $SnAuthDeviceCopyWith<$Res> { |  | ||||||
|   factory _$SnAuthDeviceCopyWith(_SnAuthDevice value, $Res Function(_SnAuthDevice) _then) = __$SnAuthDeviceCopyWithImpl; |  | ||||||
| @override @useResult |  | ||||||
| $Res call({ |  | ||||||
|  dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent |  | ||||||
| }); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
| /// @nodoc |  | ||||||
| class __$SnAuthDeviceCopyWithImpl<$Res> |  | ||||||
|     implements _$SnAuthDeviceCopyWith<$Res> { |  | ||||||
|   __$SnAuthDeviceCopyWithImpl(this._self, this._then); |  | ||||||
|  |  | ||||||
|   final _SnAuthDevice _self; |  | ||||||
|   final $Res Function(_SnAuthDevice) _then; |  | ||||||
|  |  | ||||||
| /// Create a copy of SnAuthDevice |  | ||||||
| /// with the given fields replaced by the non-null parameter values. |  | ||||||
| @override @pragma('vm:prefer-inline') $Res call({Object? label = freezed,Object? userAgent = null,Object? deviceId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) { |  | ||||||
|   return _then(_SnAuthDevice( |  | ||||||
| label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable |  | ||||||
| as dynamic,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable |  | ||||||
| as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable |  | ||||||
| as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable |  | ||||||
| as int,sessions: null == sessions ? _self._sessions : sessions // ignore: cast_nullable_to_non_nullable |  | ||||||
| as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable |  | ||||||
| as bool, |  | ||||||
|   )); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnAccountConnection { | mixin _$SnAccountConnection { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,6 +13,24 @@ Map<String, dynamic> _$AppTokenToJson(_AppToken instance) => <String, dynamic>{ | |||||||
|   'token': instance.token, |   'token': instance.token, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | _GeoIpLocation _$GeoIpLocationFromJson(Map<String, dynamic> json) => | ||||||
|  |     _GeoIpLocation( | ||||||
|  |       latitude: (json['latitude'] as num).toDouble(), | ||||||
|  |       longitude: (json['longitude'] as num).toDouble(), | ||||||
|  |       countryCode: json['country_code'] as String, | ||||||
|  |       country: json['country'] as String, | ||||||
|  |       city: json['city'] as String, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$GeoIpLocationToJson(_GeoIpLocation instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'latitude': instance.latitude, | ||||||
|  |       'longitude': instance.longitude, | ||||||
|  |       'country_code': instance.countryCode, | ||||||
|  |       'country': instance.country, | ||||||
|  |       'city': instance.city, | ||||||
|  |     }; | ||||||
|  |  | ||||||
| _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) => | _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) => | ||||||
|     _SnAuthChallenge( |     _SnAuthChallenge( | ||||||
|       id: json['id'] as String, |       id: json['id'] as String, | ||||||
| @@ -20,7 +38,6 @@ _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) => | |||||||
|       stepRemain: (json['step_remain'] as num).toInt(), |       stepRemain: (json['step_remain'] as num).toInt(), | ||||||
|       stepTotal: (json['step_total'] as num).toInt(), |       stepTotal: (json['step_total'] as num).toInt(), | ||||||
|       failedAttempts: (json['failed_attempts'] as num).toInt(), |       failedAttempts: (json['failed_attempts'] as num).toInt(), | ||||||
|       platform: (json['platform'] as num).toInt(), |  | ||||||
|       type: (json['type'] as num).toInt(), |       type: (json['type'] as num).toInt(), | ||||||
|       blacklistFactors: |       blacklistFactors: | ||||||
|           (json['blacklist_factors'] as List<dynamic>) |           (json['blacklist_factors'] as List<dynamic>) | ||||||
| @@ -30,9 +47,13 @@ _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) => | |||||||
|       scopes: json['scopes'] as List<dynamic>, |       scopes: json['scopes'] as List<dynamic>, | ||||||
|       ipAddress: json['ip_address'] as String, |       ipAddress: json['ip_address'] as String, | ||||||
|       userAgent: json['user_agent'] as String, |       userAgent: json['user_agent'] as String, | ||||||
|       deviceId: json['device_id'] as String, |  | ||||||
|       nonce: json['nonce'] as String?, |       nonce: json['nonce'] as String?, | ||||||
|       location: json['location'] as String?, |       location: | ||||||
|  |           json['location'] == null | ||||||
|  |               ? null | ||||||
|  |               : GeoIpLocation.fromJson( | ||||||
|  |                 json['location'] as Map<String, dynamic>, | ||||||
|  |               ), | ||||||
|       accountId: json['account_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), | ||||||
| @@ -49,16 +70,14 @@ Map<String, dynamic> _$SnAuthChallengeToJson(_SnAuthChallenge instance) => | |||||||
|       'step_remain': instance.stepRemain, |       'step_remain': instance.stepRemain, | ||||||
|       'step_total': instance.stepTotal, |       'step_total': instance.stepTotal, | ||||||
|       'failed_attempts': instance.failedAttempts, |       'failed_attempts': instance.failedAttempts, | ||||||
|       'platform': instance.platform, |  | ||||||
|       'type': instance.type, |       'type': instance.type, | ||||||
|       'blacklist_factors': instance.blacklistFactors, |       'blacklist_factors': instance.blacklistFactors, | ||||||
|       'audiences': instance.audiences, |       'audiences': instance.audiences, | ||||||
|       'scopes': instance.scopes, |       'scopes': instance.scopes, | ||||||
|       'ip_address': instance.ipAddress, |       'ip_address': instance.ipAddress, | ||||||
|       'user_agent': instance.userAgent, |       'user_agent': instance.userAgent, | ||||||
|       'device_id': instance.deviceId, |  | ||||||
|       'nonce': instance.nonce, |       'nonce': instance.nonce, | ||||||
|       'location': instance.location, |       'location': instance.location?.toJson(), | ||||||
|       'account_id': instance.accountId, |       'account_id': instance.accountId, | ||||||
|       'created_at': instance.createdAt.toIso8601String(), |       'created_at': instance.createdAt.toIso8601String(), | ||||||
|       'updated_at': instance.updatedAt.toIso8601String(), |       'updated_at': instance.updatedAt.toIso8601String(), | ||||||
| @@ -133,29 +152,6 @@ Map<String, dynamic> _$SnAuthFactorToJson(_SnAuthFactor instance) => | |||||||
|       'created_response': instance.createdResponse, |       'created_response': instance.createdResponse, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| _SnAuthDevice _$SnAuthDeviceFromJson(Map<String, dynamic> json) => |  | ||||||
|     _SnAuthDevice( |  | ||||||
|       label: json['label'], |  | ||||||
|       userAgent: json['user_agent'] as String, |  | ||||||
|       deviceId: json['device_id'] as String, |  | ||||||
|       platform: (json['platform'] as num).toInt(), |  | ||||||
|       sessions: |  | ||||||
|           (json['sessions'] as List<dynamic>) |  | ||||||
|               .map((e) => SnAuthSession.fromJson(e as Map<String, dynamic>)) |  | ||||||
|               .toList(), |  | ||||||
|       isCurrent: json['is_current'] as bool? ?? false, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
| Map<String, dynamic> _$SnAuthDeviceToJson(_SnAuthDevice instance) => |  | ||||||
|     <String, dynamic>{ |  | ||||||
|       'label': instance.label, |  | ||||||
|       'user_agent': instance.userAgent, |  | ||||||
|       'device_id': instance.deviceId, |  | ||||||
|       'platform': instance.platform, |  | ||||||
|       'sessions': instance.sessions.map((e) => e.toJson()).toList(), |  | ||||||
|       'is_current': instance.isCurrent, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
| _SnAccountConnection _$SnAccountConnectionFromJson(Map<String, dynamic> json) => | _SnAccountConnection _$SnAccountConnectionFromJson(Map<String, dynamic> json) => | ||||||
|     _SnAccountConnection( |     _SnAccountConnection( | ||||||
|       id: json['id'] as String, |       id: json['id'] as String, | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								lib/models/bot.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								lib/models/bot.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
|  | import 'package:island/models/account.dart'; | ||||||
|  | import 'package:island/models/developer.dart'; | ||||||
|  |  | ||||||
|  | part 'bot.freezed.dart'; | ||||||
|  | part 'bot.g.dart'; | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class Bot with _$Bot { | ||||||
|  |   const factory Bot({ | ||||||
|  |     required String id, | ||||||
|  |     required String slug, | ||||||
|  |     required bool isActive, | ||||||
|  |     required String projectId, | ||||||
|  |     required DateTime createdAt, | ||||||
|  |     required DateTime updatedAt, | ||||||
|  |     required SnAccount account, | ||||||
|  |     SnDeveloper? developer, | ||||||
|  |   }) = _Bot; | ||||||
|  |  | ||||||
|  |   factory Bot.fromJson(Map<String, dynamic> json) => _$BotFromJson(json); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class BotConfig with _$BotConfig { | ||||||
|  |   const factory BotConfig({ | ||||||
|  |     @Default(false) bool isPublic, | ||||||
|  |     @Default(false) bool isInteractive, | ||||||
|  |     @Default([]) List<String> allowedRealms, | ||||||
|  |     @Default([]) List<String> allowedChatTypes, | ||||||
|  |     @Default({}) Map<String, dynamic> metadata, | ||||||
|  |   }) = _BotConfig; | ||||||
|  |  | ||||||
|  |   factory BotConfig.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$BotConfigFromJson(json); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class BotLinks with _$BotLinks { | ||||||
|  |   const factory BotLinks({ | ||||||
|  |     String? website, | ||||||
|  |     String? documentation, | ||||||
|  |     String? privacyPolicy, | ||||||
|  |     String? termsOfService, | ||||||
|  |   }) = _BotLinks; | ||||||
|  |  | ||||||
|  |   factory BotLinks.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$BotLinksFromJson(json); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class BotSecret with _$BotSecret { | ||||||
|  |   const factory BotSecret({ | ||||||
|  |     @Default('') String id, | ||||||
|  |     @Default('') String secret, | ||||||
|  |     String? description, | ||||||
|  |     DateTime? expiredAt, | ||||||
|  |     @Default('') String botId, | ||||||
|  |   }) = _BotSecret; | ||||||
|  |  | ||||||
|  |   factory BotSecret.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$BotSecretFromJson(json); | ||||||
|  | } | ||||||
							
								
								
									
										1156
									
								
								lib/models/bot.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1156
									
								
								lib/models/bot.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										91
									
								
								lib/models/bot.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								lib/models/bot.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'bot.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // JsonSerializableGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | _Bot _$BotFromJson(Map<String, dynamic> json) => _Bot( | ||||||
|  |   id: json['id'] as String, | ||||||
|  |   slug: json['slug'] as String, | ||||||
|  |   isActive: json['is_active'] as bool, | ||||||
|  |   projectId: json['project_id'] as String, | ||||||
|  |   createdAt: DateTime.parse(json['created_at'] as String), | ||||||
|  |   updatedAt: DateTime.parse(json['updated_at'] as String), | ||||||
|  |   account: SnAccount.fromJson(json['account'] as Map<String, dynamic>), | ||||||
|  |   developer: | ||||||
|  |       json['developer'] == null | ||||||
|  |           ? null | ||||||
|  |           : SnDeveloper.fromJson(json['developer'] as Map<String, dynamic>), | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$BotToJson(_Bot instance) => <String, dynamic>{ | ||||||
|  |   'id': instance.id, | ||||||
|  |   'slug': instance.slug, | ||||||
|  |   'is_active': instance.isActive, | ||||||
|  |   'project_id': instance.projectId, | ||||||
|  |   'created_at': instance.createdAt.toIso8601String(), | ||||||
|  |   'updated_at': instance.updatedAt.toIso8601String(), | ||||||
|  |   'account': instance.account.toJson(), | ||||||
|  |   'developer': instance.developer?.toJson(), | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | _BotConfig _$BotConfigFromJson(Map<String, dynamic> json) => _BotConfig( | ||||||
|  |   isPublic: json['is_public'] as bool? ?? false, | ||||||
|  |   isInteractive: json['is_interactive'] as bool? ?? false, | ||||||
|  |   allowedRealms: | ||||||
|  |       (json['allowed_realms'] as List<dynamic>?) | ||||||
|  |           ?.map((e) => e as String) | ||||||
|  |           .toList() ?? | ||||||
|  |       const [], | ||||||
|  |   allowedChatTypes: | ||||||
|  |       (json['allowed_chat_types'] as List<dynamic>?) | ||||||
|  |           ?.map((e) => e as String) | ||||||
|  |           .toList() ?? | ||||||
|  |       const [], | ||||||
|  |   metadata: json['metadata'] as Map<String, dynamic>? ?? const {}, | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$BotConfigToJson(_BotConfig instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'is_public': instance.isPublic, | ||||||
|  |       'is_interactive': instance.isInteractive, | ||||||
|  |       'allowed_realms': instance.allowedRealms, | ||||||
|  |       'allowed_chat_types': instance.allowedChatTypes, | ||||||
|  |       'metadata': instance.metadata, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  | _BotLinks _$BotLinksFromJson(Map<String, dynamic> json) => _BotLinks( | ||||||
|  |   website: json['website'] as String?, | ||||||
|  |   documentation: json['documentation'] as String?, | ||||||
|  |   privacyPolicy: json['privacy_policy'] as String?, | ||||||
|  |   termsOfService: json['terms_of_service'] as String?, | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$BotLinksToJson(_BotLinks instance) => <String, dynamic>{ | ||||||
|  |   'website': instance.website, | ||||||
|  |   'documentation': instance.documentation, | ||||||
|  |   'privacy_policy': instance.privacyPolicy, | ||||||
|  |   'terms_of_service': instance.termsOfService, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | _BotSecret _$BotSecretFromJson(Map<String, dynamic> json) => _BotSecret( | ||||||
|  |   id: json['id'] as String? ?? '', | ||||||
|  |   secret: json['secret'] as String? ?? '', | ||||||
|  |   description: json['description'] as String?, | ||||||
|  |   expiredAt: | ||||||
|  |       json['expired_at'] == null | ||||||
|  |           ? null | ||||||
|  |           : DateTime.parse(json['expired_at'] as String), | ||||||
|  |   botId: json['bot_id'] as String? ?? '', | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$BotSecretToJson(_BotSecret instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'id': instance.id, | ||||||
|  |       'secret': instance.secret, | ||||||
|  |       'description': instance.description, | ||||||
|  |       'expired_at': instance.expiredAt?.toIso8601String(), | ||||||
|  |       'bot_id': instance.botId, | ||||||
|  |     }; | ||||||
							
								
								
									
										20
									
								
								lib/models/bot_key.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								lib/models/bot_key.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
|  |  | ||||||
|  | part 'bot_key.freezed.dart'; | ||||||
|  | part 'bot_key.g.dart'; | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class SnAccountApiKey with _$SnAccountApiKey { | ||||||
|  |   const factory SnAccountApiKey({ | ||||||
|  |     required String id, | ||||||
|  |     required String label, | ||||||
|  |     required String accountId, | ||||||
|  |     required String sessionId, | ||||||
|  |     required DateTime createdAt, | ||||||
|  |     required DateTime updatedAt, | ||||||
|  |     String? key, | ||||||
|  |   }) = _SnAccountApiKey; | ||||||
|  |  | ||||||
|  |   factory SnAccountApiKey.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$SnAccountApiKeyFromJson(json); | ||||||
|  | } | ||||||
							
								
								
									
										289
									
								
								lib/models/bot_key.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								lib/models/bot_key.freezed.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | |||||||
|  | // 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 'bot_key.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // FreezedGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | // dart format off | ||||||
|  | T _$identity<T>(T value) => value; | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | mixin _$SnAccountApiKey { | ||||||
|  |  | ||||||
|  |  String get id; String get label; String get accountId; String get sessionId; DateTime get createdAt; DateTime get updatedAt; String? get key; | ||||||
|  | /// Create a copy of SnAccountApiKey | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnAccountApiKeyCopyWith<SnAccountApiKey> get copyWith => _$SnAccountApiKeyCopyWithImpl<SnAccountApiKey>(this as SnAccountApiKey, _$identity); | ||||||
|  |  | ||||||
|  |   /// Serializes this SnAccountApiKey to a JSON map. | ||||||
|  |   Map<String, dynamic> toJson(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountApiKey&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.key, key) || other.key == key)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,label,accountId,sessionId,createdAt,updatedAt,key); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnAccountApiKey(id: $id, label: $label, accountId: $accountId, sessionId: $sessionId, createdAt: $createdAt, updatedAt: $updatedAt, key: $key)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class $SnAccountApiKeyCopyWith<$Res>  { | ||||||
|  |   factory $SnAccountApiKeyCopyWith(SnAccountApiKey value, $Res Function(SnAccountApiKey) _then) = _$SnAccountApiKeyCopyWithImpl; | ||||||
|  | @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, String label, String accountId, String sessionId, DateTime createdAt, DateTime updatedAt, String? key | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class _$SnAccountApiKeyCopyWithImpl<$Res> | ||||||
|  |     implements $SnAccountApiKeyCopyWith<$Res> { | ||||||
|  |   _$SnAccountApiKeyCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final SnAccountApiKey _self; | ||||||
|  |   final $Res Function(SnAccountApiKey) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnAccountApiKey | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? label = null,Object? accountId = null,Object? sessionId = null,Object? createdAt = null,Object? updatedAt = null,Object? key = freezed,}) { | ||||||
|  |   return _then(_self.copyWith( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,label: null == label ? _self.label : label // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,sessionId: null == sessionId ? _self.sessionId : sessionId // 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,key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Adds pattern-matching-related methods to [SnAccountApiKey]. | ||||||
|  | extension SnAccountApiKeyPatterns on SnAccountApiKey { | ||||||
|  | /// 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( _SnAccountApiKey value)?  $default,{required TResult orElse(),}){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnAccountApiKey() 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( _SnAccountApiKey value)  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnAccountApiKey(): | ||||||
|  | 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( _SnAccountApiKey value)?  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnAccountApiKey() 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,  String label,  String accountId,  String sessionId,  DateTime createdAt,  DateTime updatedAt,  String? key)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnAccountApiKey() when $default != null: | ||||||
|  | return $default(_that.id,_that.label,_that.accountId,_that.sessionId,_that.createdAt,_that.updatedAt,_that.key);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,  String label,  String accountId,  String sessionId,  DateTime createdAt,  DateTime updatedAt,  String? key)  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnAccountApiKey(): | ||||||
|  | return $default(_that.id,_that.label,_that.accountId,_that.sessionId,_that.createdAt,_that.updatedAt,_that.key);} | ||||||
|  | } | ||||||
|  | /// 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,  String label,  String accountId,  String sessionId,  DateTime createdAt,  DateTime updatedAt,  String? key)?  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnAccountApiKey() when $default != null: | ||||||
|  | return $default(_that.id,_that.label,_that.accountId,_that.sessionId,_that.createdAt,_that.updatedAt,_that.key);case _: | ||||||
|  |   return null; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | @JsonSerializable() | ||||||
|  |  | ||||||
|  | class _SnAccountApiKey implements SnAccountApiKey { | ||||||
|  |   const _SnAccountApiKey({required this.id, required this.label, required this.accountId, required this.sessionId, required this.createdAt, required this.updatedAt, this.key}); | ||||||
|  |   factory _SnAccountApiKey.fromJson(Map<String, dynamic> json) => _$SnAccountApiKeyFromJson(json); | ||||||
|  |  | ||||||
|  | @override final  String id; | ||||||
|  | @override final  String label; | ||||||
|  | @override final  String accountId; | ||||||
|  | @override final  String sessionId; | ||||||
|  | @override final  DateTime createdAt; | ||||||
|  | @override final  DateTime updatedAt; | ||||||
|  | @override final  String? key; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnAccountApiKey | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | _$SnAccountApiKeyCopyWith<_SnAccountApiKey> get copyWith => __$SnAccountApiKeyCopyWithImpl<_SnAccountApiKey>(this, _$identity); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | Map<String, dynamic> toJson() { | ||||||
|  |   return _$SnAccountApiKeyToJson(this, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountApiKey&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.key, key) || other.key == key)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,label,accountId,sessionId,createdAt,updatedAt,key); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnAccountApiKey(id: $id, label: $label, accountId: $accountId, sessionId: $sessionId, createdAt: $createdAt, updatedAt: $updatedAt, key: $key)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class _$SnAccountApiKeyCopyWith<$Res> implements $SnAccountApiKeyCopyWith<$Res> { | ||||||
|  |   factory _$SnAccountApiKeyCopyWith(_SnAccountApiKey value, $Res Function(_SnAccountApiKey) _then) = __$SnAccountApiKeyCopyWithImpl; | ||||||
|  | @override @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, String label, String accountId, String sessionId, DateTime createdAt, DateTime updatedAt, String? key | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class __$SnAccountApiKeyCopyWithImpl<$Res> | ||||||
|  |     implements _$SnAccountApiKeyCopyWith<$Res> { | ||||||
|  |   __$SnAccountApiKeyCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final _SnAccountApiKey _self; | ||||||
|  |   final $Res Function(_SnAccountApiKey) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnAccountApiKey | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? label = null,Object? accountId = null,Object? sessionId = null,Object? createdAt = null,Object? updatedAt = null,Object? key = freezed,}) { | ||||||
|  |   return _then(_SnAccountApiKey( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,label: null == label ? _self.label : label // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,sessionId: null == sessionId ? _self.sessionId : sessionId // 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,key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // dart format on | ||||||
							
								
								
									
										29
									
								
								lib/models/bot_key.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								lib/models/bot_key.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'bot_key.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // JsonSerializableGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | _SnAccountApiKey _$SnAccountApiKeyFromJson(Map<String, dynamic> json) => | ||||||
|  |     _SnAccountApiKey( | ||||||
|  |       id: json['id'] as String, | ||||||
|  |       label: json['label'] as String, | ||||||
|  |       accountId: json['account_id'] as String, | ||||||
|  |       sessionId: json['session_id'] as String, | ||||||
|  |       createdAt: DateTime.parse(json['created_at'] as String), | ||||||
|  |       updatedAt: DateTime.parse(json['updated_at'] as String), | ||||||
|  |       key: json['key'] as String?, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$SnAccountApiKeyToJson(_SnAccountApiKey instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'id': instance.id, | ||||||
|  |       'label': instance.label, | ||||||
|  |       'account_id': instance.accountId, | ||||||
|  |       'session_id': instance.sessionId, | ||||||
|  |       'created_at': instance.createdAt.toIso8601String(), | ||||||
|  |       'updated_at': instance.updatedAt.toIso8601String(), | ||||||
|  |       'key': instance.key, | ||||||
|  |     }; | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:island/models/file.dart'; | import 'package:island/models/file.dart'; | ||||||
| import 'package:island/models/realm.dart'; | import 'package:island/models/realm.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
|  |  | ||||||
| part 'chat.freezed.dart'; | part 'chat.freezed.dart'; | ||||||
| part 'chat.g.dart'; | part 'chat.g.dart'; | ||||||
| @@ -91,6 +91,7 @@ sealed class SnChatMember with _$SnChatMember { | |||||||
|     required DateTime? breakUntil, |     required DateTime? breakUntil, | ||||||
|     required DateTime? timeoutUntil, |     required DateTime? timeoutUntil, | ||||||
|     required bool isBot, |     required bool isBot, | ||||||
|  |     required SnAccountStatus? status, | ||||||
|     // Frontend data |     // Frontend data | ||||||
|     DateTime? lastTyped, |     DateTime? lastTyped, | ||||||
|   }) = _SnChatMember; |   }) = _SnChatMember; | ||||||
| @@ -103,7 +104,7 @@ sealed class SnChatMember with _$SnChatMember { | |||||||
| sealed class SnChatSummary with _$SnChatSummary { | sealed class SnChatSummary with _$SnChatSummary { | ||||||
|   const factory SnChatSummary({ |   const factory SnChatSummary({ | ||||||
|     required int unreadCount, |     required int unreadCount, | ||||||
|     required SnChatMessage lastMessage, |     required SnChatMessage? lastMessage, | ||||||
|   }) = _SnChatSummary; |   }) = _SnChatSummary; | ||||||
|  |  | ||||||
|   factory SnChatSummary.fromJson(Map<String, dynamic> json) => |   factory SnChatSummary.fromJson(Map<String, dynamic> json) => | ||||||
|   | |||||||
| @@ -1037,7 +1037,7 @@ $SnChatMemberCopyWith<$Res> get sender { | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnChatMember { | mixin _$SnChatMember { | ||||||
|  |  | ||||||
|  DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get chatRoomId; SnChatRoom? get chatRoom; String get accountId; SnAccount get account; String? get nick; int get role; int get notify; DateTime? get joinedAt; DateTime? get breakUntil; DateTime? get timeoutUntil; bool get isBot;// Frontend data |  DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get chatRoomId; SnChatRoom? get chatRoom; String get accountId; SnAccount get account; String? get nick; int get role; int get notify; DateTime? get joinedAt; DateTime? get breakUntil; DateTime? get timeoutUntil; bool get isBot; SnAccountStatus? get status;// Frontend data | ||||||
|  DateTime? get lastTyped; |  DateTime? get lastTyped; | ||||||
| /// Create a copy of SnChatMember | /// Create a copy of SnChatMember | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @@ -1051,16 +1051,16 @@ $SnChatMemberCopyWith<SnChatMember> get copyWith => _$SnChatMemberCopyWithImpl<S | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.status, status) || other.status == status)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,lastTyped); | int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,status,lastTyped); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, lastTyped: $lastTyped)'; |   return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, status: $status, lastTyped: $lastTyped)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1071,11 +1071,11 @@ abstract mixin class $SnChatMemberCopyWith<$Res>  { | |||||||
|   factory $SnChatMemberCopyWith(SnChatMember value, $Res Function(SnChatMember) _then) = _$SnChatMemberCopyWithImpl; |   factory $SnChatMemberCopyWith(SnChatMember value, $Res Function(SnChatMember) _then) = _$SnChatMemberCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped |  DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, SnAccountStatus? status, DateTime? lastTyped | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| $SnChatRoomCopyWith<$Res>? get chatRoom;$SnAccountCopyWith<$Res> get account; | $SnChatRoomCopyWith<$Res>? get chatRoom;$SnAccountCopyWith<$Res> get account;$SnAccountStatusCopyWith<$Res>? get status; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -1088,7 +1088,7 @@ class _$SnChatMemberCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnChatMember | /// Create a copy of SnChatMember | ||||||
| /// 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 = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? lastTyped = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? status = freezed,Object? lastTyped = freezed,}) { | ||||||
|   return _then(_self.copyWith( |   return _then(_self.copyWith( | ||||||
| createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | 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 | ||||||
| @@ -1105,7 +1105,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast | |||||||
| as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable | as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable | as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable | as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable | as bool,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable | ||||||
|  | as SnAccountStatus?,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?, | as DateTime?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
| @@ -1130,6 +1131,18 @@ $SnAccountCopyWith<$Res> get account { | |||||||
|   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 SnChatMember | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnAccountStatusCopyWith<$Res>? get status { | ||||||
|  |     if (_self.status == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) { | ||||||
|  |     return _then(_self.copyWith(status: value)); | ||||||
|  |   }); | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1209,10 +1222,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  String id,  String chatRoomId,  SnChatRoom? chatRoom,  String accountId,  SnAccount account,  String? nick,  int role,  int notify,  DateTime? joinedAt,  DateTime? breakUntil,  DateTime? timeoutUntil,  bool isBot,  DateTime? lastTyped)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  String id,  String chatRoomId,  SnChatRoom? chatRoom,  String accountId,  SnAccount account,  String? nick,  int role,  int notify,  DateTime? joinedAt,  DateTime? breakUntil,  DateTime? timeoutUntil,  bool isBot,  SnAccountStatus? status,  DateTime? lastTyped)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnChatMember() when $default != null: | case _SnChatMember() when $default != null: | ||||||
| return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.lastTyped);case _: | return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.status,_that.lastTyped);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -1230,10 +1243,10 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.c | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  String id,  String chatRoomId,  SnChatRoom? chatRoom,  String accountId,  SnAccount account,  String? nick,  int role,  int notify,  DateTime? joinedAt,  DateTime? breakUntil,  DateTime? timeoutUntil,  bool isBot,  DateTime? lastTyped)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  String id,  String chatRoomId,  SnChatRoom? chatRoom,  String accountId,  SnAccount account,  String? nick,  int role,  int notify,  DateTime? joinedAt,  DateTime? breakUntil,  DateTime? timeoutUntil,  bool isBot,  SnAccountStatus? status,  DateTime? lastTyped)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnChatMember(): | case _SnChatMember(): | ||||||
| return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.lastTyped);} | return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.status,_that.lastTyped);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -1247,10 +1260,10 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.c | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  String id,  String chatRoomId,  SnChatRoom? chatRoom,  String accountId,  SnAccount account,  String? nick,  int role,  int notify,  DateTime? joinedAt,  DateTime? breakUntil,  DateTime? timeoutUntil,  bool isBot,  DateTime? lastTyped)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  String id,  String chatRoomId,  SnChatRoom? chatRoom,  String accountId,  SnAccount account,  String? nick,  int role,  int notify,  DateTime? joinedAt,  DateTime? breakUntil,  DateTime? timeoutUntil,  bool isBot,  SnAccountStatus? status,  DateTime? lastTyped)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnChatMember() when $default != null: | case _SnChatMember() when $default != null: | ||||||
| return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.lastTyped);case _: | return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.status,_that.lastTyped);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -1262,7 +1275,7 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.c | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnChatMember implements SnChatMember { | class _SnChatMember implements SnChatMember { | ||||||
|   const _SnChatMember({required this.createdAt, required this.updatedAt, required this.deletedAt, required this.id, required this.chatRoomId, required this.chatRoom, required this.accountId, required this.account, required this.nick, required this.role, required this.notify, required this.joinedAt, required this.breakUntil, required this.timeoutUntil, required this.isBot, this.lastTyped}); |   const _SnChatMember({required this.createdAt, required this.updatedAt, required this.deletedAt, required this.id, required this.chatRoomId, required this.chatRoom, required this.accountId, required this.account, required this.nick, required this.role, required this.notify, required this.joinedAt, required this.breakUntil, required this.timeoutUntil, required this.isBot, required this.status, this.lastTyped}); | ||||||
|   factory _SnChatMember.fromJson(Map<String, dynamic> json) => _$SnChatMemberFromJson(json); |   factory _SnChatMember.fromJson(Map<String, dynamic> json) => _$SnChatMemberFromJson(json); | ||||||
|  |  | ||||||
| @override final  DateTime createdAt; | @override final  DateTime createdAt; | ||||||
| @@ -1280,6 +1293,7 @@ class _SnChatMember implements SnChatMember { | |||||||
| @override final  DateTime? breakUntil; | @override final  DateTime? breakUntil; | ||||||
| @override final  DateTime? timeoutUntil; | @override final  DateTime? timeoutUntil; | ||||||
| @override final  bool isBot; | @override final  bool isBot; | ||||||
|  | @override final  SnAccountStatus? status; | ||||||
| // Frontend data | // Frontend data | ||||||
| @override final  DateTime? lastTyped; | @override final  DateTime? lastTyped; | ||||||
|  |  | ||||||
| @@ -1296,16 +1310,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.status, status) || other.status == status)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,lastTyped); | int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,status,lastTyped); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, lastTyped: $lastTyped)'; |   return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, status: $status, lastTyped: $lastTyped)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1316,11 +1330,11 @@ abstract mixin class _$SnChatMemberCopyWith<$Res> implements $SnChatMemberCopyWi | |||||||
|   factory _$SnChatMemberCopyWith(_SnChatMember value, $Res Function(_SnChatMember) _then) = __$SnChatMemberCopyWithImpl; |   factory _$SnChatMemberCopyWith(_SnChatMember value, $Res Function(_SnChatMember) _then) = __$SnChatMemberCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped |  DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, SnAccountStatus? status, DateTime? lastTyped | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @override $SnChatRoomCopyWith<$Res>? get chatRoom;@override $SnAccountCopyWith<$Res> get account; | @override $SnChatRoomCopyWith<$Res>? get chatRoom;@override $SnAccountCopyWith<$Res> get account;@override $SnAccountStatusCopyWith<$Res>? get status; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -1333,7 +1347,7 @@ class __$SnChatMemberCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnChatMember | /// Create a copy of SnChatMember | ||||||
| /// 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 = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? lastTyped = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? status = freezed,Object? lastTyped = freezed,}) { | ||||||
|   return _then(_SnChatMember( |   return _then(_SnChatMember( | ||||||
| createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | 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 | ||||||
| @@ -1350,7 +1364,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast | |||||||
| as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable | as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable | as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable | as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable | as bool,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable | ||||||
|  | as SnAccountStatus?,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?, | as DateTime?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
| @@ -1376,6 +1391,18 @@ $SnAccountCopyWith<$Res> get account { | |||||||
|   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 SnChatMember | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnAccountStatusCopyWith<$Res>? get status { | ||||||
|  |     if (_self.status == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) { | ||||||
|  |     return _then(_self.copyWith(status: value)); | ||||||
|  |   }); | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1383,7 +1410,7 @@ $SnAccountCopyWith<$Res> get account { | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnChatSummary { | mixin _$SnChatSummary { | ||||||
|  |  | ||||||
|  int get unreadCount; SnChatMessage get lastMessage; |  int get unreadCount; SnChatMessage? get lastMessage; | ||||||
| /// Create a copy of SnChatSummary | /// Create a copy of SnChatSummary | ||||||
| /// 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) | ||||||
| @@ -1416,11 +1443,11 @@ abstract mixin class $SnChatSummaryCopyWith<$Res>  { | |||||||
|   factory $SnChatSummaryCopyWith(SnChatSummary value, $Res Function(SnChatSummary) _then) = _$SnChatSummaryCopyWithImpl; |   factory $SnChatSummaryCopyWith(SnChatSummary value, $Res Function(SnChatSummary) _then) = _$SnChatSummaryCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  int unreadCount, SnChatMessage lastMessage |  int unreadCount, SnChatMessage? lastMessage | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| $SnChatMessageCopyWith<$Res> get lastMessage; | $SnChatMessageCopyWith<$Res>? get lastMessage; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -1433,20 +1460,23 @@ class _$SnChatSummaryCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnChatSummary | /// Create a copy of SnChatSummary | ||||||
| /// 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? unreadCount = null,Object? lastMessage = null,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? unreadCount = null,Object? lastMessage = freezed,}) { | ||||||
|   return _then(_self.copyWith( |   return _then(_self.copyWith( | ||||||
| unreadCount: null == unreadCount ? _self.unreadCount : unreadCount // ignore: cast_nullable_to_non_nullable | unreadCount: null == unreadCount ? _self.unreadCount : unreadCount // ignore: cast_nullable_to_non_nullable | ||||||
| as int,lastMessage: null == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable | as int,lastMessage: freezed == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable | ||||||
| as SnChatMessage, | as SnChatMessage?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
| /// Create a copy of SnChatSummary | /// Create a copy of SnChatSummary | ||||||
| /// 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') | ||||||
| $SnChatMessageCopyWith<$Res> get lastMessage { | $SnChatMessageCopyWith<$Res>? get lastMessage { | ||||||
|  |     if (_self.lastMessage == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   return $SnChatMessageCopyWith<$Res>(_self.lastMessage, (value) { |   return $SnChatMessageCopyWith<$Res>(_self.lastMessage!, (value) { | ||||||
|     return _then(_self.copyWith(lastMessage: value)); |     return _then(_self.copyWith(lastMessage: value)); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| @@ -1528,7 +1558,7 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int unreadCount,  SnChatMessage lastMessage)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int unreadCount,  SnChatMessage? lastMessage)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnChatSummary() when $default != null: | case _SnChatSummary() when $default != null: | ||||||
| return $default(_that.unreadCount,_that.lastMessage);case _: | return $default(_that.unreadCount,_that.lastMessage);case _: | ||||||
| @@ -1549,7 +1579,7 @@ return $default(_that.unreadCount,_that.lastMessage);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int unreadCount,  SnChatMessage lastMessage)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int unreadCount,  SnChatMessage? lastMessage)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnChatSummary(): | case _SnChatSummary(): | ||||||
| return $default(_that.unreadCount,_that.lastMessage);} | return $default(_that.unreadCount,_that.lastMessage);} | ||||||
| @@ -1566,7 +1596,7 @@ return $default(_that.unreadCount,_that.lastMessage);} | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int unreadCount,  SnChatMessage lastMessage)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int unreadCount,  SnChatMessage? lastMessage)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnChatSummary() when $default != null: | case _SnChatSummary() when $default != null: | ||||||
| return $default(_that.unreadCount,_that.lastMessage);case _: | return $default(_that.unreadCount,_that.lastMessage);case _: | ||||||
| @@ -1585,7 +1615,7 @@ class _SnChatSummary implements SnChatSummary { | |||||||
|   factory _SnChatSummary.fromJson(Map<String, dynamic> json) => _$SnChatSummaryFromJson(json); |   factory _SnChatSummary.fromJson(Map<String, dynamic> json) => _$SnChatSummaryFromJson(json); | ||||||
|  |  | ||||||
| @override final  int unreadCount; | @override final  int unreadCount; | ||||||
| @override final  SnChatMessage lastMessage; | @override final  SnChatMessage? lastMessage; | ||||||
|  |  | ||||||
| /// Create a copy of SnChatSummary | /// Create a copy of SnChatSummary | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @@ -1620,11 +1650,11 @@ abstract mixin class _$SnChatSummaryCopyWith<$Res> implements $SnChatSummaryCopy | |||||||
|   factory _$SnChatSummaryCopyWith(_SnChatSummary value, $Res Function(_SnChatSummary) _then) = __$SnChatSummaryCopyWithImpl; |   factory _$SnChatSummaryCopyWith(_SnChatSummary value, $Res Function(_SnChatSummary) _then) = __$SnChatSummaryCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  int unreadCount, SnChatMessage lastMessage |  int unreadCount, SnChatMessage? lastMessage | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @override $SnChatMessageCopyWith<$Res> get lastMessage; | @override $SnChatMessageCopyWith<$Res>? get lastMessage; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -1637,11 +1667,11 @@ class __$SnChatSummaryCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnChatSummary | /// Create a copy of SnChatSummary | ||||||
| /// 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? unreadCount = null,Object? lastMessage = null,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? unreadCount = null,Object? lastMessage = freezed,}) { | ||||||
|   return _then(_SnChatSummary( |   return _then(_SnChatSummary( | ||||||
| unreadCount: null == unreadCount ? _self.unreadCount : unreadCount // ignore: cast_nullable_to_non_nullable | unreadCount: null == unreadCount ? _self.unreadCount : unreadCount // ignore: cast_nullable_to_non_nullable | ||||||
| as int,lastMessage: null == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable | as int,lastMessage: freezed == lastMessage ? _self.lastMessage : lastMessage // ignore: cast_nullable_to_non_nullable | ||||||
| as SnChatMessage, | as SnChatMessage?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1649,9 +1679,12 @@ as SnChatMessage, | |||||||
| /// 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') | ||||||
| $SnChatMessageCopyWith<$Res> get lastMessage { | $SnChatMessageCopyWith<$Res>? get lastMessage { | ||||||
|  |     if (_self.lastMessage == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   return $SnChatMessageCopyWith<$Res>(_self.lastMessage, (value) { |   return $SnChatMessageCopyWith<$Res>(_self.lastMessage!, (value) { | ||||||
|     return _then(_self.copyWith(lastMessage: value)); |     return _then(_self.copyWith(lastMessage: value)); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -177,6 +177,12 @@ _SnChatMember _$SnChatMemberFromJson(Map<String, dynamic> json) => | |||||||
|               ? null |               ? null | ||||||
|               : DateTime.parse(json['timeout_until'] as String), |               : DateTime.parse(json['timeout_until'] as String), | ||||||
|       isBot: json['is_bot'] as bool, |       isBot: json['is_bot'] as bool, | ||||||
|  |       status: | ||||||
|  |           json['status'] == null | ||||||
|  |               ? null | ||||||
|  |               : SnAccountStatus.fromJson( | ||||||
|  |                 json['status'] as Map<String, dynamic>, | ||||||
|  |               ), | ||||||
|       lastTyped: |       lastTyped: | ||||||
|           json['last_typed'] == null |           json['last_typed'] == null | ||||||
|               ? null |               ? null | ||||||
| @@ -200,13 +206,17 @@ Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) => | |||||||
|       'break_until': instance.breakUntil?.toIso8601String(), |       'break_until': instance.breakUntil?.toIso8601String(), | ||||||
|       'timeout_until': instance.timeoutUntil?.toIso8601String(), |       'timeout_until': instance.timeoutUntil?.toIso8601String(), | ||||||
|       'is_bot': instance.isBot, |       'is_bot': instance.isBot, | ||||||
|  |       'status': instance.status?.toJson(), | ||||||
|       'last_typed': instance.lastTyped?.toIso8601String(), |       'last_typed': instance.lastTyped?.toIso8601String(), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| _SnChatSummary _$SnChatSummaryFromJson(Map<String, dynamic> json) => | _SnChatSummary _$SnChatSummaryFromJson(Map<String, dynamic> json) => | ||||||
|     _SnChatSummary( |     _SnChatSummary( | ||||||
|       unreadCount: (json['unread_count'] as num).toInt(), |       unreadCount: (json['unread_count'] as num).toInt(), | ||||||
|       lastMessage: SnChatMessage.fromJson( |       lastMessage: | ||||||
|  |           json['last_message'] == null | ||||||
|  |               ? null | ||||||
|  |               : SnChatMessage.fromJson( | ||||||
|                 json['last_message'] as Map<String, dynamic>, |                 json['last_message'] as Map<String, dynamic>, | ||||||
|               ), |               ), | ||||||
|     ); |     ); | ||||||
| @@ -214,7 +224,7 @@ _SnChatSummary _$SnChatSummaryFromJson(Map<String, dynamic> json) => | |||||||
| Map<String, dynamic> _$SnChatSummaryToJson(_SnChatSummary instance) => | Map<String, dynamic> _$SnChatSummaryToJson(_SnChatSummary instance) => | ||||||
|     <String, dynamic>{ |     <String, dynamic>{ | ||||||
|       'unread_count': instance.unreadCount, |       'unread_count': instance.unreadCount, | ||||||
|       'last_message': instance.lastMessage.toJson(), |       'last_message': instance.lastMessage?.toJson(), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| _MessageChange _$MessageChangeFromJson(Map<String, dynamic> json) => | _MessageChange _$MessageChangeFromJson(Map<String, dynamic> json) => | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:island/models/file.dart'; | import 'package:island/models/file.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
|  |  | ||||||
| part 'custom_app.freezed.dart'; | part 'custom_app.freezed.dart'; | ||||||
| part 'custom_app.g.dart'; | part 'custom_app.g.dart'; | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								lib/models/custom_app_secret.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/models/custom_app_secret.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
|  |  | ||||||
|  | part 'custom_app_secret.freezed.dart'; | ||||||
|  | part 'custom_app_secret.g.dart'; | ||||||
|  |  | ||||||
|  | @freezed | ||||||
|  | sealed class CustomAppSecret with _$CustomAppSecret { | ||||||
|  |   const factory CustomAppSecret({ | ||||||
|  |     required String id, | ||||||
|  |     required String? secret, | ||||||
|  |     required DateTime createdAt, | ||||||
|  |     String? description, | ||||||
|  |     int? expiresIn, | ||||||
|  |     bool? isOidc, | ||||||
|  |   }) = _CustomAppSecret; | ||||||
|  |  | ||||||
|  |   factory CustomAppSecret.fromJson(Map<String, dynamic> json) => | ||||||
|  |       _$CustomAppSecretFromJson(json); | ||||||
|  | } | ||||||
							
								
								
									
										286
									
								
								lib/models/custom_app_secret.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								lib/models/custom_app_secret.freezed.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,286 @@ | |||||||
|  | // 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 'custom_app_secret.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // FreezedGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | // dart format off | ||||||
|  | T _$identity<T>(T value) => value; | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | mixin _$CustomAppSecret { | ||||||
|  |  | ||||||
|  |  String get id; String? get secret; DateTime get createdAt; String? get description; int? get expiresIn; bool? get isOidc; | ||||||
|  | /// Create a copy of CustomAppSecret | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $CustomAppSecretCopyWith<CustomAppSecret> get copyWith => _$CustomAppSecretCopyWithImpl<CustomAppSecret>(this as CustomAppSecret, _$identity); | ||||||
|  |  | ||||||
|  |   /// Serializes this CustomAppSecret to a JSON map. | ||||||
|  |   Map<String, dynamic> toJson(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is CustomAppSecret&&(identical(other.id, id) || other.id == id)&&(identical(other.secret, secret) || other.secret == secret)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.description, description) || other.description == description)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.isOidc, isOidc) || other.isOidc == isOidc)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,secret,createdAt,description,expiresIn,isOidc); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'CustomAppSecret(id: $id, secret: $secret, createdAt: $createdAt, description: $description, expiresIn: $expiresIn, isOidc: $isOidc)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class $CustomAppSecretCopyWith<$Res>  { | ||||||
|  |   factory $CustomAppSecretCopyWith(CustomAppSecret value, $Res Function(CustomAppSecret) _then) = _$CustomAppSecretCopyWithImpl; | ||||||
|  | @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, String? secret, DateTime createdAt, String? description, int? expiresIn, bool? isOidc | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class _$CustomAppSecretCopyWithImpl<$Res> | ||||||
|  |     implements $CustomAppSecretCopyWith<$Res> { | ||||||
|  |   _$CustomAppSecretCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final CustomAppSecret _self; | ||||||
|  |   final $Res Function(CustomAppSecret) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of CustomAppSecret | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? secret = freezed,Object? createdAt = null,Object? description = freezed,Object? expiresIn = freezed,Object? isOidc = freezed,}) { | ||||||
|  |   return _then(_self.copyWith( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,secret: freezed == secret ? _self.secret : secret // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,expiresIn: freezed == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int?,isOidc: freezed == isOidc ? _self.isOidc : isOidc // ignore: cast_nullable_to_non_nullable | ||||||
|  | as bool?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Adds pattern-matching-related methods to [CustomAppSecret]. | ||||||
|  | extension CustomAppSecretPatterns on CustomAppSecret { | ||||||
|  | /// 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( _CustomAppSecret value)?  $default,{required TResult orElse(),}){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _CustomAppSecret() 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( _CustomAppSecret value)  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _CustomAppSecret(): | ||||||
|  | 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( _CustomAppSecret value)?  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _CustomAppSecret() 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,  String? secret,  DateTime createdAt,  String? description,  int? expiresIn,  bool? isOidc)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _CustomAppSecret() when $default != null: | ||||||
|  | return $default(_that.id,_that.secret,_that.createdAt,_that.description,_that.expiresIn,_that.isOidc);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,  String? secret,  DateTime createdAt,  String? description,  int? expiresIn,  bool? isOidc)  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _CustomAppSecret(): | ||||||
|  | return $default(_that.id,_that.secret,_that.createdAt,_that.description,_that.expiresIn,_that.isOidc);} | ||||||
|  | } | ||||||
|  | /// 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,  String? secret,  DateTime createdAt,  String? description,  int? expiresIn,  bool? isOidc)?  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _CustomAppSecret() when $default != null: | ||||||
|  | return $default(_that.id,_that.secret,_that.createdAt,_that.description,_that.expiresIn,_that.isOidc);case _: | ||||||
|  |   return null; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | @JsonSerializable() | ||||||
|  |  | ||||||
|  | class _CustomAppSecret implements CustomAppSecret { | ||||||
|  |   const _CustomAppSecret({required this.id, required this.secret, required this.createdAt, this.description, this.expiresIn, this.isOidc}); | ||||||
|  |   factory _CustomAppSecret.fromJson(Map<String, dynamic> json) => _$CustomAppSecretFromJson(json); | ||||||
|  |  | ||||||
|  | @override final  String id; | ||||||
|  | @override final  String? secret; | ||||||
|  | @override final  DateTime createdAt; | ||||||
|  | @override final  String? description; | ||||||
|  | @override final  int? expiresIn; | ||||||
|  | @override final  bool? isOidc; | ||||||
|  |  | ||||||
|  | /// Create a copy of CustomAppSecret | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | _$CustomAppSecretCopyWith<_CustomAppSecret> get copyWith => __$CustomAppSecretCopyWithImpl<_CustomAppSecret>(this, _$identity); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | Map<String, dynamic> toJson() { | ||||||
|  |   return _$CustomAppSecretToJson(this, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _CustomAppSecret&&(identical(other.id, id) || other.id == id)&&(identical(other.secret, secret) || other.secret == secret)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.description, description) || other.description == description)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.isOidc, isOidc) || other.isOidc == isOidc)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,secret,createdAt,description,expiresIn,isOidc); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'CustomAppSecret(id: $id, secret: $secret, createdAt: $createdAt, description: $description, expiresIn: $expiresIn, isOidc: $isOidc)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class _$CustomAppSecretCopyWith<$Res> implements $CustomAppSecretCopyWith<$Res> { | ||||||
|  |   factory _$CustomAppSecretCopyWith(_CustomAppSecret value, $Res Function(_CustomAppSecret) _then) = __$CustomAppSecretCopyWithImpl; | ||||||
|  | @override @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, String? secret, DateTime createdAt, String? description, int? expiresIn, bool? isOidc | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class __$CustomAppSecretCopyWithImpl<$Res> | ||||||
|  |     implements _$CustomAppSecretCopyWith<$Res> { | ||||||
|  |   __$CustomAppSecretCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final _CustomAppSecret _self; | ||||||
|  |   final $Res Function(_CustomAppSecret) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of CustomAppSecret | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? secret = freezed,Object? createdAt = null,Object? description = freezed,Object? expiresIn = freezed,Object? isOidc = freezed,}) { | ||||||
|  |   return _then(_CustomAppSecret( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,secret: freezed == secret ? _self.secret : secret // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,expiresIn: freezed == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int?,isOidc: freezed == isOidc ? _self.isOidc : isOidc // ignore: cast_nullable_to_non_nullable | ||||||
|  | as bool?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // dart format on | ||||||
							
								
								
									
										27
									
								
								lib/models/custom_app_secret.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/models/custom_app_secret.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'custom_app_secret.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // JsonSerializableGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | _CustomAppSecret _$CustomAppSecretFromJson(Map<String, dynamic> json) => | ||||||
|  |     _CustomAppSecret( | ||||||
|  |       id: json['id'] as String, | ||||||
|  |       secret: json['secret'] as String?, | ||||||
|  |       createdAt: DateTime.parse(json['created_at'] as String), | ||||||
|  |       description: json['description'] as String?, | ||||||
|  |       expiresIn: (json['expires_in'] as num?)?.toInt(), | ||||||
|  |       isOidc: json['is_oidc'] as bool?, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  | Map<String, dynamic> _$CustomAppSecretToJson(_CustomAppSecret instance) => | ||||||
|  |     <String, dynamic>{ | ||||||
|  |       'id': instance.id, | ||||||
|  |       'secret': instance.secret, | ||||||
|  |       'created_at': instance.createdAt.toIso8601String(), | ||||||
|  |       'description': instance.description, | ||||||
|  |       'expires_in': instance.expiresIn, | ||||||
|  |       'is_oidc': instance.isOidc, | ||||||
|  |     }; | ||||||
							
								
								
									
										23
									
								
								lib/models/dev_project.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/models/dev_project.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  |  | ||||||
|  | class DevProject { | ||||||
|  |   final String id; | ||||||
|  |   final String slug; | ||||||
|  |   final String name; | ||||||
|  |   final String? description; | ||||||
|  |  | ||||||
|  |   DevProject({ | ||||||
|  |     required this.id, | ||||||
|  |     required this.slug, | ||||||
|  |     required this.name, | ||||||
|  |     this.description, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   factory DevProject.fromJson(Map<String, dynamic> json) { | ||||||
|  |     return DevProject( | ||||||
|  |       id: json['id'], | ||||||
|  |       slug: json['slug'], | ||||||
|  |       name: json['name'], | ||||||
|  |       description: json['description'], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -11,8 +11,8 @@ sealed class SnScrappedLink with _$SnScrappedLink { | |||||||
|     required String title, |     required String title, | ||||||
|     required String? description, |     required String? description, | ||||||
|     required String? imageUrl, |     required String? imageUrl, | ||||||
|     required String faviconUrl, |     required String? faviconUrl, | ||||||
|     required String siteName, |     required String? siteName, | ||||||
|     required String? contentType, |     required String? contentType, | ||||||
|     required String? author, |     required String? author, | ||||||
|     required DateTime? publishedDate, |     required DateTime? publishedDate, | ||||||
|   | |||||||
| @@ -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,16 +65,16 @@ 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 = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) { | @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,}) { | ||||||
|   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: null == 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: null == 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: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable | as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable | ||||||
| as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable | as String?,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable | as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable | as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?, | as DateTime?, | ||||||
| @@ -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 _: | ||||||
| @@ -220,8 +220,8 @@ class _SnScrappedLink implements SnScrappedLink { | |||||||
| @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; | ||||||
| @override final  String siteName; | @override final  String? siteName; | ||||||
| @override final  String? contentType; | @override final  String? contentType; | ||||||
| @override final  String? author; | @override final  String? author; | ||||||
| @override final  DateTime? publishedDate; | @override final  DateTime? publishedDate; | ||||||
| @@ -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,16 +276,16 @@ 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 = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) { | @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,}) { | ||||||
|   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: null == 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: null == 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: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable | as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable | ||||||
| as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable | as String?,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable | as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable | as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?, | as DateTime?, | ||||||
|   | |||||||
| @@ -13,8 +13,8 @@ _SnScrappedLink _$SnScrappedLinkFromJson(Map<String, dynamic> json) => | |||||||
|       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?, | ||||||
|       siteName: json['site_name'] as String, |       siteName: json['site_name'] as String?, | ||||||
|       contentType: json['content_type'] as String?, |       contentType: json['content_type'] as String?, | ||||||
|       author: json['author'] as String?, |       author: json['author'] as String?, | ||||||
|       publishedDate: |       publishedDate: | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import 'package:island/models/file.dart'; | |||||||
| import 'package:island/models/post_category.dart'; | import 'package:island/models/post_category.dart'; | ||||||
| import 'package:island/models/post_tag.dart'; | import 'package:island/models/post_tag.dart'; | ||||||
| import 'package:island/models/publisher.dart'; | import 'package:island/models/publisher.dart'; | ||||||
|  | import 'package:island/models/realm.dart'; | ||||||
|  |  | ||||||
| part 'post.freezed.dart'; | part 'post.freezed.dart'; | ||||||
| part 'post.g.dart'; | part 'post.g.dart'; | ||||||
| @@ -18,6 +19,7 @@ sealed class SnPost with _$SnPost { | |||||||
|     @Default(null) DateTime? publishedAt, |     @Default(null) DateTime? publishedAt, | ||||||
|     @Default(0) int visibility, |     @Default(0) int visibility, | ||||||
|     String? content, |     String? content, | ||||||
|  |     String? slug, | ||||||
|     @Default(0) int type, |     @Default(0) int type, | ||||||
|     Map<String, dynamic>? meta, |     Map<String, dynamic>? meta, | ||||||
|     @Default(0) int viewsUnique, |     @Default(0) int viewsUnique, | ||||||
| @@ -25,12 +27,15 @@ sealed class SnPost with _$SnPost { | |||||||
|     @Default(0) int upvotes, |     @Default(0) int upvotes, | ||||||
|     @Default(0) int downvotes, |     @Default(0) int downvotes, | ||||||
|     @Default(0) int repliesCount, |     @Default(0) int repliesCount, | ||||||
|  |     int? pinMode, | ||||||
|     String? threadedPostId, |     String? threadedPostId, | ||||||
|     SnPost? threadedPost, |     SnPost? threadedPost, | ||||||
|     String? repliedPostId, |     String? repliedPostId, | ||||||
|     SnPost? repliedPost, |     SnPost? repliedPost, | ||||||
|     String? forwardedPostId, |     String? forwardedPostId, | ||||||
|     SnPost? forwardedPost, |     SnPost? forwardedPost, | ||||||
|  |     String? realmId, | ||||||
|  |     SnRealm? realm, | ||||||
|     @Default([]) List<SnCloudFile> attachments, |     @Default([]) List<SnCloudFile> attachments, | ||||||
|     required SnPublisher publisher, |     required SnPublisher publisher, | ||||||
|     @Default({}) Map<String, int> reactionsCount, |     @Default({}) Map<String, int> reactionsCount, | ||||||
|   | |||||||
| @@ -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; int get type; Map<String, dynamic>? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; 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; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; 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; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; 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; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; 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.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(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.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)&&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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(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.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.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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(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,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,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),createdAt,updatedAt,deletedAt,isTruncated]); | int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,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),createdAt,updatedAt,deletedAt,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, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, 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, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, 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, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, 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, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, 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, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| $SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnPublisherCopyWith<$Res> get publisher; | $SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res> get publisher; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @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? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = 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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,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? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = 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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,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 | ||||||
| @@ -75,6 +75,7 @@ as String?,editedAt: freezed == editedAt ? _self.editedAt : editedAt // ignore: | |||||||
| as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable | as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable | as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable | ||||||
| as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable | as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,slug: freezed == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||||
| as int,meta: freezed == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable | as int,meta: freezed == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable | ||||||
| as Map<String, dynamic>?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable | as Map<String, dynamic>?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -82,13 +83,16 @@ as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore: | |||||||
| as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | ||||||
| as int,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | as int,pinMode: freezed == pinMode ? _self.pinMode : pinMode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int?,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | ||||||
| as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | ||||||
| as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId : forwardedPostId // ignore: cast_nullable_to_non_nullable | as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId : forwardedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| 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?,attachments: null == attachments ? _self.attachments : attachments // 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 SnRealm?,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable | as List<SnCloudFile>,publisher: null == 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,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 | ||||||
| @@ -143,6 +147,18 @@ $SnPostCopyWith<$Res>? get forwardedPost { | |||||||
| /// 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') | ||||||
|  | $SnRealmCopyWith<$Res>? get realm { | ||||||
|  |     if (_self.realm == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnRealmCopyWith<$Res>(_self.realm!, (value) { | ||||||
|  |     return _then(_self.copyWith(realm: value)); | ||||||
|  |   }); | ||||||
|  | }/// Create a copy of SnPost | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
| $SnPublisherCopyWith<$Res> get publisher { | $SnPublisherCopyWith<$Res> get publisher { | ||||||
|    |    | ||||||
|   return $SnPublisherCopyWith<$Res>(_self.publisher, (value) { |   return $SnPublisherCopyWith<$Res>(_self.publisher, (value) { | ||||||
| @@ -227,10 +243,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,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  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,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  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,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  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,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  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.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_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.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -248,10 +264,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,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  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,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  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,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  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,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  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.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_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.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -265,10 +281,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,  int type,  Map<String, dynamic>? meta,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  String? threadedPostId,  SnPost? threadedPost,  String? repliedPostId,  SnPost? repliedPost,  String? forwardedPostId,  SnPost? forwardedPost,  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,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  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,  int viewsUnique,  int viewsTotal,  int upvotes,  int downvotes,  int repliesCount,  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,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt,  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.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_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.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -280,7 +296,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.type = 0, final  Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, final  List<SnCloudFile> attachments = const [], required this.publisher, final  Map<String, int> reactionsCount = const {}, final  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 [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; |   const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final  Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 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 [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; | ||||||
|   factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json); |   factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @@ -291,6 +307,7 @@ class _SnPost implements SnPost { | |||||||
| @override@JsonKey() final  DateTime? publishedAt; | @override@JsonKey() final  DateTime? publishedAt; | ||||||
| @override@JsonKey() final  int visibility; | @override@JsonKey() final  int visibility; | ||||||
| @override final  String? content; | @override final  String? content; | ||||||
|  | @override final  String? slug; | ||||||
| @override@JsonKey() final  int type; | @override@JsonKey() final  int type; | ||||||
|  final  Map<String, dynamic>? _meta; |  final  Map<String, dynamic>? _meta; | ||||||
| @override Map<String, dynamic>? get meta { | @override Map<String, dynamic>? get meta { | ||||||
| @@ -306,12 +323,15 @@ class _SnPost implements SnPost { | |||||||
| @override@JsonKey() final  int upvotes; | @override@JsonKey() final  int upvotes; | ||||||
| @override@JsonKey() final  int downvotes; | @override@JsonKey() final  int downvotes; | ||||||
| @override@JsonKey() final  int repliesCount; | @override@JsonKey() final  int repliesCount; | ||||||
|  | @override final  int? pinMode; | ||||||
| @override final  String? threadedPostId; | @override final  String? threadedPostId; | ||||||
| @override final  SnPost? threadedPost; | @override final  SnPost? threadedPost; | ||||||
| @override final  String? repliedPostId; | @override final  String? repliedPostId; | ||||||
| @override final  SnPost? repliedPost; | @override final  SnPost? repliedPost; | ||||||
| @override final  String? forwardedPostId; | @override final  String? forwardedPostId; | ||||||
| @override final  SnPost? forwardedPost; | @override final  SnPost? forwardedPost; | ||||||
|  | @override final  String? realmId; | ||||||
|  | @override final  SnRealm? realm; | ||||||
|  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; | ||||||
| @@ -380,16 +400,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.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(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.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)&&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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(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.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.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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(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,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,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),createdAt,updatedAt,deletedAt,isTruncated]); | int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,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),createdAt,updatedAt,deletedAt,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, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, 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, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, 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, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -400,11 +420,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, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, 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, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnPublisherCopyWith<$Res> get publisher; | @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; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -417,7 +437,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? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = 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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,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? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = 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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,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 | ||||||
| @@ -427,6 +447,7 @@ as String?,editedAt: freezed == editedAt ? _self.editedAt : editedAt // ignore: | |||||||
| as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable | as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable | ||||||
| as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable | as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable | ||||||
| as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable | as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,slug: freezed == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable | ||||||
| as int,meta: freezed == meta ? _self._meta : meta // ignore: cast_nullable_to_non_nullable | as int,meta: freezed == meta ? _self._meta : meta // ignore: cast_nullable_to_non_nullable | ||||||
| as Map<String, dynamic>?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable | as Map<String, dynamic>?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -434,13 +455,16 @@ as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore: | |||||||
| as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable | ||||||
| as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable | ||||||
| as int,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | as int,pinMode: freezed == pinMode ? _self.pinMode : pinMode // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int?,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable | ||||||
| as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable | ||||||
| as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId : forwardedPostId // ignore: cast_nullable_to_non_nullable | as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId : forwardedPostId // ignore: cast_nullable_to_non_nullable | ||||||
| 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?,attachments: null == attachments ? _self._attachments : attachments // 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 SnRealm?,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable | as List<SnCloudFile>,publisher: null == 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,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 | ||||||
| @@ -496,6 +520,18 @@ $SnPostCopyWith<$Res>? get forwardedPost { | |||||||
| /// 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') | ||||||
|  | $SnRealmCopyWith<$Res>? get realm { | ||||||
|  |     if (_self.realm == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnRealmCopyWith<$Res>(_self.realm!, (value) { | ||||||
|  |     return _then(_self.copyWith(realm: value)); | ||||||
|  |   }); | ||||||
|  | }/// Create a copy of SnPost | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
| $SnPublisherCopyWith<$Res> get publisher { | $SnPublisherCopyWith<$Res> get publisher { | ||||||
|    |    | ||||||
|   return $SnPublisherCopyWith<$Res>(_self.publisher, (value) { |   return $SnPublisherCopyWith<$Res>(_self.publisher, (value) { | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost( | |||||||
|           : DateTime.parse(json['published_at'] as String), |           : DateTime.parse(json['published_at'] as String), | ||||||
|   visibility: (json['visibility'] as num?)?.toInt() ?? 0, |   visibility: (json['visibility'] as num?)?.toInt() ?? 0, | ||||||
|   content: json['content'] as String?, |   content: json['content'] as String?, | ||||||
|  |   slug: json['slug'] as String?, | ||||||
|   type: (json['type'] as num?)?.toInt() ?? 0, |   type: (json['type'] as num?)?.toInt() ?? 0, | ||||||
|   meta: json['meta'] as Map<String, dynamic>?, |   meta: json['meta'] as Map<String, dynamic>?, | ||||||
|   viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0, |   viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0, | ||||||
| @@ -28,6 +29,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost( | |||||||
|   upvotes: (json['upvotes'] as num?)?.toInt() ?? 0, |   upvotes: (json['upvotes'] as num?)?.toInt() ?? 0, | ||||||
|   downvotes: (json['downvotes'] as num?)?.toInt() ?? 0, |   downvotes: (json['downvotes'] as num?)?.toInt() ?? 0, | ||||||
|   repliesCount: (json['replies_count'] as num?)?.toInt() ?? 0, |   repliesCount: (json['replies_count'] as num?)?.toInt() ?? 0, | ||||||
|  |   pinMode: (json['pin_mode'] as num?)?.toInt(), | ||||||
|   threadedPostId: json['threaded_post_id'] as String?, |   threadedPostId: json['threaded_post_id'] as String?, | ||||||
|   threadedPost: |   threadedPost: | ||||||
|       json['threaded_post'] == null |       json['threaded_post'] == null | ||||||
| @@ -43,6 +45,11 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost( | |||||||
|       json['forwarded_post'] == null |       json['forwarded_post'] == null | ||||||
|           ? null |           ? null | ||||||
|           : SnPost.fromJson(json['forwarded_post'] as Map<String, dynamic>), |           : SnPost.fromJson(json['forwarded_post'] as Map<String, dynamic>), | ||||||
|  |   realmId: json['realm_id'] as String?, | ||||||
|  |   realm: | ||||||
|  |       json['realm'] == null | ||||||
|  |           ? null | ||||||
|  |           : SnRealm.fromJson(json['realm'] as Map<String, dynamic>), | ||||||
|   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>)) | ||||||
| @@ -95,6 +102,7 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{ | |||||||
|   'published_at': instance.publishedAt?.toIso8601String(), |   'published_at': instance.publishedAt?.toIso8601String(), | ||||||
|   'visibility': instance.visibility, |   'visibility': instance.visibility, | ||||||
|   'content': instance.content, |   'content': instance.content, | ||||||
|  |   'slug': instance.slug, | ||||||
|   'type': instance.type, |   'type': instance.type, | ||||||
|   'meta': instance.meta, |   'meta': instance.meta, | ||||||
|   'views_unique': instance.viewsUnique, |   'views_unique': instance.viewsUnique, | ||||||
| @@ -102,12 +110,15 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{ | |||||||
|   'upvotes': instance.upvotes, |   'upvotes': instance.upvotes, | ||||||
|   'downvotes': instance.downvotes, |   'downvotes': instance.downvotes, | ||||||
|   'replies_count': instance.repliesCount, |   'replies_count': instance.repliesCount, | ||||||
|  |   'pin_mode': instance.pinMode, | ||||||
|   'threaded_post_id': instance.threadedPostId, |   'threaded_post_id': instance.threadedPostId, | ||||||
|   'threaded_post': instance.threadedPost?.toJson(), |   'threaded_post': instance.threadedPost?.toJson(), | ||||||
|   'replied_post_id': instance.repliedPostId, |   'replied_post_id': instance.repliedPostId, | ||||||
|   'replied_post': instance.repliedPost?.toJson(), |   'replied_post': instance.repliedPost?.toJson(), | ||||||
|   'forwarded_post_id': instance.forwardedPostId, |   'forwarded_post_id': instance.forwardedPostId, | ||||||
|   'forwarded_post': instance.forwardedPost?.toJson(), |   'forwarded_post': instance.forwardedPost?.toJson(), | ||||||
|  |   'realm_id': instance.realmId, | ||||||
|  |   'realm': instance.realm?.toJson(), | ||||||
|   'attachments': instance.attachments.map((e) => e.toJson()).toList(), |   'attachments': instance.attachments.map((e) => e.toJson()).toList(), | ||||||
|   'publisher': instance.publisher.toJson(), |   'publisher': instance.publisher.toJson(), | ||||||
|   'reactions_count': instance.reactionsCount, |   'reactions_count': instance.reactionsCount, | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:island/models/post.dart'; | import 'package:island/models/post.dart'; | ||||||
| import 'package:island/services/text.dart'; | import 'package:island/utils/text.dart'; | ||||||
|  |  | ||||||
| part 'post_category.freezed.dart'; | part 'post_category.freezed.dart'; | ||||||
| part 'post_category.g.dart'; | part 'post_category.g.dart'; | ||||||
| @@ -15,6 +15,7 @@ sealed class SnPostCategory with _$SnPostCategory { | |||||||
|     required String slug, |     required String slug, | ||||||
|     String? name, |     String? name, | ||||||
|     @Default([]) List<SnPost> posts, |     @Default([]) List<SnPost> posts, | ||||||
|  |     @Default(0) int usage, | ||||||
|   }) = _SnPostCategory; |   }) = _SnPostCategory; | ||||||
|  |  | ||||||
|   factory SnPostCategory.fromJson(Map<String, dynamic> json) => |   factory SnPostCategory.fromJson(Map<String, dynamic> json) => | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ T _$identity<T>(T value) => value; | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnPostCategory { | mixin _$SnPostCategory { | ||||||
|  |  | ||||||
|  String get id; String get slug; String? get name; List<SnPost> get posts; |  String get id; String get slug; String? get name; List<SnPost> get posts; int get usage; | ||||||
| /// Create a copy of SnPostCategory | /// Create a copy of SnPostCategory | ||||||
| /// 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 @@ $SnPostCategoryCopyWith<SnPostCategory> get copyWith => _$SnPostCategoryCopyWith | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts)&&(identical(other.usage, usage) || other.usage == usage)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts)); | int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts),usage); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts)'; |   return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -48,7 +48,7 @@ abstract mixin class $SnPostCategoryCopyWith<$Res>  { | |||||||
|   factory $SnPostCategoryCopyWith(SnPostCategory value, $Res Function(SnPostCategory) _then) = _$SnPostCategoryCopyWithImpl; |   factory $SnPostCategoryCopyWith(SnPostCategory value, $Res Function(SnPostCategory) _then) = _$SnPostCategoryCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String slug, String? name, List<SnPost> posts |  String id, String slug, String? name, List<SnPost> posts, int usage | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -65,13 +65,14 @@ class _$SnPostCategoryCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnPostCategory | /// Create a copy of SnPostCategory | ||||||
| /// 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? slug = null,Object? name = freezed,Object? posts = null,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = 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,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||||
| as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,posts: null == posts ? _self.posts : posts // ignore: cast_nullable_to_non_nullable | as String?,posts: null == posts ? _self.posts : posts // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnPost>, | as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -153,10 +154,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts,  int usage)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPostCategory() when $default != null: | case _SnPostCategory() when $default != null: | ||||||
| return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -174,10 +175,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts,  int usage)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPostCategory(): | case _SnPostCategory(): | ||||||
| return $default(_that.id,_that.slug,_that.name,_that.posts);} | return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -191,10 +192,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);} | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String slug,  String? name,  List<SnPost> posts)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String slug,  String? name,  List<SnPost> posts,  int usage)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPostCategory() when $default != null: | case _SnPostCategory() when $default != null: | ||||||
| return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -206,7 +207,7 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnPostCategory extends SnPostCategory { | class _SnPostCategory extends SnPostCategory { | ||||||
|   const _SnPostCategory({required this.id, required this.slug, this.name, final  List<SnPost> posts = const []}): _posts = posts,super._(); |   const _SnPostCategory({required this.id, required this.slug, this.name, final  List<SnPost> posts = const [], this.usage = 0}): _posts = posts,super._(); | ||||||
|   factory _SnPostCategory.fromJson(Map<String, dynamic> json) => _$SnPostCategoryFromJson(json); |   factory _SnPostCategory.fromJson(Map<String, dynamic> json) => _$SnPostCategoryFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @@ -219,6 +220,7 @@ class _SnPostCategory extends SnPostCategory { | |||||||
|   return EqualUnmodifiableListView(_posts); |   return EqualUnmodifiableListView(_posts); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @override@JsonKey() final  int usage; | ||||||
|  |  | ||||||
| /// Create a copy of SnPostCategory | /// Create a copy of SnPostCategory | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @@ -233,16 +235,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostCategory&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts)&&(identical(other.usage, usage) || other.usage == usage)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts)); | int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts),usage); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts)'; |   return 'SnPostCategory(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -253,7 +255,7 @@ abstract mixin class _$SnPostCategoryCopyWith<$Res> implements $SnPostCategoryCo | |||||||
|   factory _$SnPostCategoryCopyWith(_SnPostCategory value, $Res Function(_SnPostCategory) _then) = __$SnPostCategoryCopyWithImpl; |   factory _$SnPostCategoryCopyWith(_SnPostCategory value, $Res Function(_SnPostCategory) _then) = __$SnPostCategoryCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String slug, String? name, List<SnPost> posts |  String id, String slug, String? name, List<SnPost> posts, int usage | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -270,13 +272,14 @@ class __$SnPostCategoryCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnPostCategory | /// Create a copy of SnPostCategory | ||||||
| /// 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? slug = null,Object? name = freezed,Object? posts = null,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = null,}) { | ||||||
|   return _then(_SnPostCategory( |   return _then(_SnPostCategory( | ||||||
| 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,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||||
| as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,posts: null == posts ? _self._posts : posts // ignore: cast_nullable_to_non_nullable | as String?,posts: null == posts ? _self._posts : posts // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnPost>, | as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ _SnPostCategory _$SnPostCategoryFromJson(Map<String, dynamic> json) => | |||||||
|               ?.map((e) => SnPost.fromJson(e as Map<String, dynamic>)) |               ?.map((e) => SnPost.fromJson(e as Map<String, dynamic>)) | ||||||
|               .toList() ?? |               .toList() ?? | ||||||
|           const [], |           const [], | ||||||
|  |       usage: (json['usage'] as num?)?.toInt() ?? 0, | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
| Map<String, dynamic> _$SnPostCategoryToJson(_SnPostCategory instance) => | Map<String, dynamic> _$SnPostCategoryToJson(_SnPostCategory instance) => | ||||||
| @@ -24,4 +25,5 @@ Map<String, dynamic> _$SnPostCategoryToJson(_SnPostCategory instance) => | |||||||
|       'slug': instance.slug, |       'slug': instance.slug, | ||||||
|       'name': instance.name, |       'name': instance.name, | ||||||
|       'posts': instance.posts.map((e) => e.toJson()).toList(), |       'posts': instance.posts.map((e) => e.toJson()).toList(), | ||||||
|  |       'usage': instance.usage, | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ sealed class SnPostTag with _$SnPostTag { | |||||||
|     required String slug, |     required String slug, | ||||||
|     String? name, |     String? name, | ||||||
|     @Default([]) List<SnPost> posts, |     @Default([]) List<SnPost> posts, | ||||||
|  |     @Default(0) int usage, | ||||||
|   }) = _SnPostTag; |   }) = _SnPostTag; | ||||||
|  |  | ||||||
|   factory SnPostTag.fromJson(Map<String, dynamic> json) => |   factory SnPostTag.fromJson(Map<String, dynamic> json) => | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ T _$identity<T>(T value) => value; | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnPostTag { | mixin _$SnPostTag { | ||||||
|  |  | ||||||
|  String get id; String get slug; String? get name; List<SnPost> get posts; |  String get id; String get slug; String? get name; List<SnPost> get posts; int get usage; | ||||||
| /// Create a copy of SnPostTag | /// Create a copy of SnPostTag | ||||||
| /// 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 @@ $SnPostTagCopyWith<SnPostTag> get copyWith => _$SnPostTagCopyWithImpl<SnPostTag> | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other.posts, posts)&&(identical(other.usage, usage) || other.usage == usage)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts)); | int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(posts),usage); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts)'; |   return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -48,7 +48,7 @@ abstract mixin class $SnPostTagCopyWith<$Res>  { | |||||||
|   factory $SnPostTagCopyWith(SnPostTag value, $Res Function(SnPostTag) _then) = _$SnPostTagCopyWithImpl; |   factory $SnPostTagCopyWith(SnPostTag value, $Res Function(SnPostTag) _then) = _$SnPostTagCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String slug, String? name, List<SnPost> posts |  String id, String slug, String? name, List<SnPost> posts, int usage | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -65,13 +65,14 @@ class _$SnPostTagCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnPostTag | /// Create a copy of SnPostTag | ||||||
| /// 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? slug = null,Object? name = freezed,Object? posts = null,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = 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,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||||
| as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,posts: null == posts ? _self.posts : posts // ignore: cast_nullable_to_non_nullable | as String?,posts: null == posts ? _self.posts : posts // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnPost>, | as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -153,10 +154,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts,  int usage)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPostTag() when $default != null: | case _SnPostTag() when $default != null: | ||||||
| return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -174,10 +175,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String slug,  String? name,  List<SnPost> posts,  int usage)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPostTag(): | case _SnPostTag(): | ||||||
| return $default(_that.id,_that.slug,_that.name,_that.posts);} | return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -191,10 +192,10 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);} | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String slug,  String? name,  List<SnPost> posts)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String slug,  String? name,  List<SnPost> posts,  int usage)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnPostTag() when $default != null: | case _SnPostTag() when $default != null: | ||||||
| return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | return $default(_that.id,_that.slug,_that.name,_that.posts,_that.usage);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -206,7 +207,7 @@ return $default(_that.id,_that.slug,_that.name,_that.posts);case _: | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnPostTag implements SnPostTag { | class _SnPostTag implements SnPostTag { | ||||||
|   const _SnPostTag({required this.id, required this.slug, this.name, final  List<SnPost> posts = const []}): _posts = posts; |   const _SnPostTag({required this.id, required this.slug, this.name, final  List<SnPost> posts = const [], this.usage = 0}): _posts = posts; | ||||||
|   factory _SnPostTag.fromJson(Map<String, dynamic> json) => _$SnPostTagFromJson(json); |   factory _SnPostTag.fromJson(Map<String, dynamic> json) => _$SnPostTagFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @@ -219,6 +220,7 @@ class _SnPostTag implements SnPostTag { | |||||||
|   return EqualUnmodifiableListView(_posts); |   return EqualUnmodifiableListView(_posts); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @override@JsonKey() final  int usage; | ||||||
|  |  | ||||||
| /// Create a copy of SnPostTag | /// Create a copy of SnPostTag | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @@ -233,16 +235,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostTag&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.name, name) || other.name == name)&&const DeepCollectionEquality().equals(other._posts, _posts)&&(identical(other.usage, usage) || other.usage == usage)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts)); | int get hashCode => Object.hash(runtimeType,id,slug,name,const DeepCollectionEquality().hash(_posts),usage); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts)'; |   return 'SnPostTag(id: $id, slug: $slug, name: $name, posts: $posts, usage: $usage)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -253,7 +255,7 @@ abstract mixin class _$SnPostTagCopyWith<$Res> implements $SnPostTagCopyWith<$Re | |||||||
|   factory _$SnPostTagCopyWith(_SnPostTag value, $Res Function(_SnPostTag) _then) = __$SnPostTagCopyWithImpl; |   factory _$SnPostTagCopyWith(_SnPostTag value, $Res Function(_SnPostTag) _then) = __$SnPostTagCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String slug, String? name, List<SnPost> posts |  String id, String slug, String? name, List<SnPost> posts, int usage | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -270,13 +272,14 @@ class __$SnPostTagCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnPostTag | /// Create a copy of SnPostTag | ||||||
| /// 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? slug = null,Object? name = freezed,Object? posts = null,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? name = freezed,Object? posts = null,Object? usage = null,}) { | ||||||
|   return _then(_SnPostTag( |   return _then(_SnPostTag( | ||||||
| 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,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable | ||||||
| as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as String,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,posts: null == posts ? _self._posts : posts // ignore: cast_nullable_to_non_nullable | as String?,posts: null == posts ? _self._posts : posts // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnPost>, | as List<SnPost>,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ _SnPostTag _$SnPostTagFromJson(Map<String, dynamic> json) => _SnPostTag( | |||||||
|           ?.map((e) => SnPost.fromJson(e as Map<String, dynamic>)) |           ?.map((e) => SnPost.fromJson(e as Map<String, dynamic>)) | ||||||
|           .toList() ?? |           .toList() ?? | ||||||
|       const [], |       const [], | ||||||
|  |   usage: (json['usage'] as num?)?.toInt() ?? 0, | ||||||
| ); | ); | ||||||
|  |  | ||||||
| Map<String, dynamic> _$SnPostTagToJson(_SnPostTag instance) => | Map<String, dynamic> _$SnPostTagToJson(_SnPostTag instance) => | ||||||
| @@ -23,4 +24,5 @@ Map<String, dynamic> _$SnPostTagToJson(_SnPostTag instance) => | |||||||
|       'slug': instance.slug, |       'slug': instance.slug, | ||||||
|       'name': instance.name, |       'name': instance.name, | ||||||
|       'posts': instance.posts.map((e) => e.toJson()).toList(), |       'posts': instance.posts.map((e) => e.toJson()).toList(), | ||||||
|  |       'usage': instance.usage, | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:island/models/file.dart'; | import 'package:island/models/file.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
|  |  | ||||||
| part 'publisher.freezed.dart'; | part 'publisher.freezed.dart'; | ||||||
| part 'publisher.g.dart'; | part 'publisher.g.dart'; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:island/models/file.dart'; | import 'package:island/models/file.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
|  |  | ||||||
| part 'realm.freezed.dart'; | part 'realm.freezed.dart'; | ||||||
| part 'realm.g.dart'; | part 'realm.g.dart'; | ||||||
| @@ -40,6 +40,7 @@ sealed class SnRealmMember with _$SnRealmMember { | |||||||
|     required DateTime createdAt, |     required DateTime createdAt, | ||||||
|     required DateTime updatedAt, |     required DateTime updatedAt, | ||||||
|     required DateTime? deletedAt, |     required DateTime? deletedAt, | ||||||
|  |     required SnAccountStatus? status, | ||||||
|   }) = _SnRealmMember; |   }) = _SnRealmMember; | ||||||
|  |  | ||||||
|   factory SnRealmMember.fromJson(Map<String, dynamic> json) => |   factory SnRealmMember.fromJson(Map<String, dynamic> json) => | ||||||
|   | |||||||
| @@ -359,7 +359,7 @@ $SnCloudFileCopyWith<$Res>? get background { | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnRealmMember { | mixin _$SnRealmMember { | ||||||
|  |  | ||||||
|  String get realmId; SnRealm? get realm; String get accountId; SnAccount? get account; int get role; DateTime? get joinedAt; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; |  String get realmId; SnRealm? get realm; String get accountId; SnAccount? get account; int get role; DateTime? get joinedAt; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; SnAccountStatus? get status; | ||||||
| /// Create a copy of SnRealmMember | /// Create a copy of SnRealmMember | ||||||
| /// 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) | ||||||
| @@ -372,16 +372,16 @@ $SnRealmMemberCopyWith<SnRealmMember> get copyWith => _$SnRealmMemberCopyWithImp | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.status, status) || other.status == status)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt); | int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt,status); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, status: $status)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -392,11 +392,11 @@ abstract mixin class $SnRealmMemberCopyWith<$Res>  { | |||||||
|   factory $SnRealmMemberCopyWith(SnRealmMember value, $Res Function(SnRealmMember) _then) = _$SnRealmMemberCopyWithImpl; |   factory $SnRealmMemberCopyWith(SnRealmMember value, $Res Function(SnRealmMember) _then) = _$SnRealmMemberCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccountStatus? status | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| $SnRealmCopyWith<$Res>? get realm;$SnAccountCopyWith<$Res>? get account; | $SnRealmCopyWith<$Res>? get realm;$SnAccountCopyWith<$Res>? get account;$SnAccountStatusCopyWith<$Res>? get status; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -409,7 +409,7 @@ class _$SnRealmMemberCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnRealmMember | /// Create a copy of SnRealmMember | ||||||
| /// 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? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? status = freezed,}) { | ||||||
|   return _then(_self.copyWith( |   return _then(_self.copyWith( | ||||||
| realmId: null == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable | realmId: null == 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 | ||||||
| @@ -420,7 +420,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast | |||||||
| as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // 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,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?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable | ||||||
|  | as SnAccountStatus?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
| /// Create a copy of SnRealmMember | /// Create a copy of SnRealmMember | ||||||
| @@ -447,6 +448,18 @@ $SnAccountCopyWith<$Res>? get account { | |||||||
|   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 SnRealmMember | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnAccountStatusCopyWith<$Res>? get status { | ||||||
|  |     if (_self.status == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) { | ||||||
|  |     return _then(_self.copyWith(status: value)); | ||||||
|  |   }); | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -526,10 +539,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String realmId,  SnRealm? realm,  String accountId,  SnAccount? account,  int role,  DateTime? joinedAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String realmId,  SnRealm? realm,  String accountId,  SnAccount? account,  int role,  DateTime? joinedAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  SnAccountStatus? status)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnRealmMember() when $default != null: | case _SnRealmMember() when $default != null: | ||||||
| return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.status);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -547,10 +560,10 @@ return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.ro | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String realmId,  SnRealm? realm,  String accountId,  SnAccount? account,  int role,  DateTime? joinedAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String realmId,  SnRealm? realm,  String accountId,  SnAccount? account,  int role,  DateTime? joinedAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  SnAccountStatus? status)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnRealmMember(): | case _SnRealmMember(): | ||||||
| return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt);} | return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.status);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -564,10 +577,10 @@ return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.ro | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String realmId,  SnRealm? realm,  String accountId,  SnAccount? account,  int role,  DateTime? joinedAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String realmId,  SnRealm? realm,  String accountId,  SnAccount? account,  int role,  DateTime? joinedAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt,  SnAccountStatus? status)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnRealmMember() when $default != null: | case _SnRealmMember() when $default != null: | ||||||
| return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.status);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -579,7 +592,7 @@ return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.ro | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnRealmMember implements SnRealmMember { | class _SnRealmMember implements SnRealmMember { | ||||||
|   const _SnRealmMember({required this.realmId, required this.realm, required this.accountId, required this.account, required this.role, required this.joinedAt, required this.createdAt, required this.updatedAt, required this.deletedAt}); |   const _SnRealmMember({required this.realmId, required this.realm, required this.accountId, required this.account, required this.role, required this.joinedAt, required this.createdAt, required this.updatedAt, required this.deletedAt, required this.status}); | ||||||
|   factory _SnRealmMember.fromJson(Map<String, dynamic> json) => _$SnRealmMemberFromJson(json); |   factory _SnRealmMember.fromJson(Map<String, dynamic> json) => _$SnRealmMemberFromJson(json); | ||||||
|  |  | ||||||
| @override final  String realmId; | @override final  String realmId; | ||||||
| @@ -591,6 +604,7 @@ class _SnRealmMember implements SnRealmMember { | |||||||
| @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  SnAccountStatus? status; | ||||||
|  |  | ||||||
| /// Create a copy of SnRealmMember | /// Create a copy of SnRealmMember | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @@ -605,16 +619,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.status, status) || other.status == status)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @JsonKey(includeFromJson: false, includeToJson: false) | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt); | int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt,status); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, status: $status)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -625,11 +639,11 @@ abstract mixin class _$SnRealmMemberCopyWith<$Res> implements $SnRealmMemberCopy | |||||||
|   factory _$SnRealmMemberCopyWith(_SnRealmMember value, $Res Function(_SnRealmMember) _then) = __$SnRealmMemberCopyWithImpl; |   factory _$SnRealmMemberCopyWith(_SnRealmMember value, $Res Function(_SnRealmMember) _then) = __$SnRealmMemberCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccountStatus? status | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @override $SnRealmCopyWith<$Res>? get realm;@override $SnAccountCopyWith<$Res>? get account; | @override $SnRealmCopyWith<$Res>? get realm;@override $SnAccountCopyWith<$Res>? get account;@override $SnAccountStatusCopyWith<$Res>? get status; | ||||||
|  |  | ||||||
| } | } | ||||||
| /// @nodoc | /// @nodoc | ||||||
| @@ -642,7 +656,7 @@ class __$SnRealmMemberCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnRealmMember | /// Create a copy of SnRealmMember | ||||||
| /// 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? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? status = freezed,}) { | ||||||
|   return _then(_SnRealmMember( |   return _then(_SnRealmMember( | ||||||
| realmId: null == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable | realmId: null == 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 | ||||||
| @@ -653,7 +667,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast | |||||||
| as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // 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,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?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable | ||||||
|  | as SnAccountStatus?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -681,6 +696,18 @@ $SnAccountCopyWith<$Res>? get account { | |||||||
|   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 SnRealmMember | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnAccountStatusCopyWith<$Res>? get status { | ||||||
|  |     if (_self.status == null) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) { | ||||||
|  |     return _then(_self.copyWith(status: value)); | ||||||
|  |   }); | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -75,6 +75,12 @@ _SnRealmMember _$SnRealmMemberFromJson(Map<String, dynamic> json) => | |||||||
|           json['deleted_at'] == null |           json['deleted_at'] == null | ||||||
|               ? null |               ? null | ||||||
|               : DateTime.parse(json['deleted_at'] as String), |               : DateTime.parse(json['deleted_at'] as String), | ||||||
|  |       status: | ||||||
|  |           json['status'] == null | ||||||
|  |               ? null | ||||||
|  |               : SnAccountStatus.fromJson( | ||||||
|  |                 json['status'] as Map<String, dynamic>, | ||||||
|  |               ), | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
| Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember instance) => | Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember instance) => | ||||||
| @@ -88,4 +94,5 @@ Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember 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(), | ||||||
|  |       'status': instance.status?.toJson(), | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
|  |  | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
|  |  | ||||||
| part 'relationship.freezed.dart'; | part 'relationship.freezed.dart'; | ||||||
| part 'relationship.g.dart'; | part 'relationship.g.dart'; | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
|  |  | ||||||
| part 'wallet.freezed.dart'; | part 'wallet.freezed.dart'; | ||||||
| part 'wallet.g.dart'; | part 'wallet.g.dart'; | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; | |||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/models/chat.dart'; | import 'package:island/models/chat.dart'; | ||||||
|  | import 'package:wakelock_plus/wakelock_plus.dart'; | ||||||
|  |  | ||||||
| part 'call.g.dart'; | part 'call.g.dart'; | ||||||
| part 'call.freezed.dart'; | part 'call.freezed.dart'; | ||||||
| @@ -54,7 +55,7 @@ sealed class CallParticipantLive with _$CallParticipantLive { | |||||||
|   bool get hasAudio => remoteParticipant.hasAudio; |   bool get hasAudio => remoteParticipant.hasAudio; | ||||||
| } | } | ||||||
|  |  | ||||||
| @riverpod | @Riverpod(keepAlive: true) | ||||||
| class CallNotifier extends _$CallNotifier { | class CallNotifier extends _$CallNotifier { | ||||||
|   Room? _room; |   Room? _room; | ||||||
|   LocalParticipant? _localParticipant; |   LocalParticipant? _localParticipant; | ||||||
| @@ -277,14 +278,27 @@ class CallNotifier extends _$CallNotifier { | |||||||
|  |  | ||||||
|         // Listen for connection updates |         // Listen for connection updates | ||||||
|         _room!.addListener(() { |         _room!.addListener(() { | ||||||
|  |           final wasConnected = state.isConnected; | ||||||
|  |           final isNowConnected = | ||||||
|  |               _room!.connectionState == ConnectionState.connected; | ||||||
|           state = state.copyWith( |           state = state.copyWith( | ||||||
|             isConnected: _room!.connectionState == ConnectionState.connected, |             isConnected: isNowConnected, | ||||||
|             isMicrophoneEnabled: _localParticipant!.isMicrophoneEnabled(), |             isMicrophoneEnabled: _localParticipant!.isMicrophoneEnabled(), | ||||||
|             isCameraEnabled: _localParticipant!.isCameraEnabled(), |             isCameraEnabled: _localParticipant!.isCameraEnabled(), | ||||||
|             isScreenSharing: _localParticipant!.isScreenShareEnabled(), |             isScreenSharing: _localParticipant!.isScreenShareEnabled(), | ||||||
|           ); |           ); | ||||||
|  |           // Enable wakelock when call connects | ||||||
|  |           if (!wasConnected && isNowConnected) { | ||||||
|  |             WakelockPlus.enable(); | ||||||
|  |           } | ||||||
|  |           // Disable wakelock when call disconnects | ||||||
|  |           else if (wasConnected && !isNowConnected) { | ||||||
|  |             WakelockPlus.disable(); | ||||||
|  |           } | ||||||
|         }); |         }); | ||||||
|         state = state.copyWith(isConnected: true); |         state = state.copyWith(isConnected: true); | ||||||
|  |         // Enable wakelock when call connects | ||||||
|  |         WakelockPlus.enable(); | ||||||
|       } else { |       } else { | ||||||
|         state = state.copyWith(error: 'Failed to join room'); |         state = state.copyWith(error: 'Failed to join room'); | ||||||
|       } |       } | ||||||
| @@ -344,6 +358,8 @@ class CallNotifier extends _$CallNotifier { | |||||||
|         isCameraEnabled: false, |         isCameraEnabled: false, | ||||||
|         isScreenSharing: false, |         isScreenSharing: false, | ||||||
|       ); |       ); | ||||||
|  |       // Disable wakelock when call disconnects | ||||||
|  |       WakelockPlus.disable(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -381,5 +397,7 @@ class CallNotifier extends _$CallNotifier { | |||||||
|     _durationTimer?.cancel(); |     _durationTimer?.cancel(); | ||||||
|     _roomId = null; |     _roomId = null; | ||||||
|     participantsVolumes = {}; |     participantsVolumes = {}; | ||||||
|  |     // Disable wakelock when disposing | ||||||
|  |     WakelockPlus.disable(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,22 +6,19 @@ part of 'call.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$callNotifierHash() => r'18fb807f067eecd3ea42631c1426c3e5f1fb4280'; | String _$callNotifierHash() => r'eb9bd41b97e9b5e9d54007c8327edb6567458846'; | ||||||
|  |  | ||||||
| /// See also [CallNotifier]. | /// See also [CallNotifier]. | ||||||
| @ProviderFor(CallNotifier) | @ProviderFor(CallNotifier) | ||||||
| final callNotifierProvider = | final callNotifierProvider = NotifierProvider<CallNotifier, CallState>.internal( | ||||||
|     AutoDisposeNotifierProvider<CallNotifier, CallState>.internal( |  | ||||||
|   CallNotifier.new, |   CallNotifier.new, | ||||||
|   name: r'callNotifierProvider', |   name: r'callNotifierProvider', | ||||||
|   debugGetCreateSourceHash: |   debugGetCreateSourceHash: | ||||||
|           const bool.fromEnvironment('dart.vm.product') |       const bool.fromEnvironment('dart.vm.product') ? null : _$callNotifierHash, | ||||||
|               ? null |  | ||||||
|               : _$callNotifierHash, |  | ||||||
|   dependencies: null, |   dependencies: null, | ||||||
|   allTransitiveDependencies: null, |   allTransitiveDependencies: null, | ||||||
| ); | ); | ||||||
|  |  | ||||||
| typedef _$CallNotifier = AutoDisposeNotifier<CallState>; | typedef _$CallNotifier = Notifier<CallState>; | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
|   | |||||||
| @@ -15,14 +15,18 @@ const kNetworkServerStoreKey = 'app_server_url'; | |||||||
|  |  | ||||||
| const kAppbarTransparentStoreKey = 'app_bar_transparent'; | const kAppbarTransparentStoreKey = 'app_bar_transparent'; | ||||||
| const kAppBackgroundStoreKey = 'app_has_background'; | const kAppBackgroundStoreKey = 'app_has_background'; | ||||||
|  | const kAppShowBackgroundImage = 'app_show_background_image'; | ||||||
| const kAppColorSchemeStoreKey = 'app_color_scheme'; | const kAppColorSchemeStoreKey = 'app_color_scheme'; | ||||||
| const kAppNotifyWithHaptic = 'app_notify_with_haptic'; | const kAppNotifyWithHaptic = 'app_notify_with_haptic'; | ||||||
| const kAppCustomFonts = 'app_custom_fonts'; | const kAppCustomFonts = 'app_custom_fonts'; | ||||||
| const kAppAutoTranslate = 'app_auto_translate'; | const kAppAutoTranslate = 'app_auto_translate'; | ||||||
|  | const kAppDataSavingMode = 'app_data_saving_mode'; | ||||||
| const kAppSoundEffects = 'app_sound_effects'; | const kAppSoundEffects = 'app_sound_effects'; | ||||||
| const kAppAprilFoolFeatures = 'app_april_fool_features'; | const kAppAprilFoolFeatures = 'app_april_fool_features'; | ||||||
| const kAppWindowSize = 'app_window_size'; | const kAppWindowSize = 'app_window_size'; | ||||||
| const kAppEnterToSend = 'app_enter_to_send'; | const kAppEnterToSend = 'app_enter_to_send'; | ||||||
|  | const kFeaturedPostsCollapsedId = | ||||||
|  |     'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post | ||||||
|  |  | ||||||
| const Map<String, FilterQuality> kImageQualityLevel = { | const Map<String, FilterQuality> kImageQualityLevel = { | ||||||
|   'settingsImageQualityLowest': FilterQuality.none, |   'settingsImageQualityLowest': FilterQuality.none, | ||||||
| @@ -52,10 +56,12 @@ final serverUrlProvider = Provider<String>((ref) { | |||||||
| sealed class AppSettings with _$AppSettings { | sealed class AppSettings with _$AppSettings { | ||||||
|   const factory AppSettings({ |   const factory AppSettings({ | ||||||
|     required bool autoTranslate, |     required bool autoTranslate, | ||||||
|  |     required bool dataSavingMode, | ||||||
|     required bool soundEffects, |     required bool soundEffects, | ||||||
|     required bool aprilFoolFeatures, |     required bool aprilFoolFeatures, | ||||||
|     required bool enterToSend, |     required bool enterToSend, | ||||||
|     required bool appBarTransparent, |     required bool appBarTransparent, | ||||||
|  |     required bool showBackgroundImage, | ||||||
|     required String? customFonts, |     required String? customFonts, | ||||||
|     required int? appColorScheme, // The color stored via the int type |     required int? appColorScheme, // The color stored via the int type | ||||||
|     required Size? windowSize, // The window size for desktop platforms |     required Size? windowSize, // The window size for desktop platforms | ||||||
| @@ -69,10 +75,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier { | |||||||
|     final prefs = ref.watch(sharedPreferencesProvider); |     final prefs = ref.watch(sharedPreferencesProvider); | ||||||
|     return AppSettings( |     return AppSettings( | ||||||
|       autoTranslate: prefs.getBool(kAppAutoTranslate) ?? false, |       autoTranslate: prefs.getBool(kAppAutoTranslate) ?? false, | ||||||
|  |       dataSavingMode: prefs.getBool(kAppDataSavingMode) ?? false, | ||||||
|       soundEffects: prefs.getBool(kAppSoundEffects) ?? true, |       soundEffects: prefs.getBool(kAppSoundEffects) ?? true, | ||||||
|       aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true, |       aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true, | ||||||
|       enterToSend: prefs.getBool(kAppEnterToSend) ?? true, |       enterToSend: prefs.getBool(kAppEnterToSend) ?? true, | ||||||
|       appBarTransparent: prefs.getBool(kAppbarTransparentStoreKey) ?? false, |       appBarTransparent: prefs.getBool(kAppbarTransparentStoreKey) ?? false, | ||||||
|  |       showBackgroundImage: prefs.getBool(kAppShowBackgroundImage) ?? true, | ||||||
|       customFonts: prefs.getString(kAppCustomFonts), |       customFonts: prefs.getString(kAppCustomFonts), | ||||||
|       appColorScheme: prefs.getInt(kAppColorSchemeStoreKey), |       appColorScheme: prefs.getInt(kAppColorSchemeStoreKey), | ||||||
|       windowSize: _getWindowSizeFromPrefs(prefs), |       windowSize: _getWindowSizeFromPrefs(prefs), | ||||||
| @@ -102,6 +110,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier { | |||||||
|     state = state.copyWith(autoTranslate: value); |     state = state.copyWith(autoTranslate: value); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void setDataSavingMode(bool value){ | ||||||
|  |     final prefs = ref.read(sharedPreferencesProvider); | ||||||
|  |     prefs.setBool(kAppDataSavingMode, value); | ||||||
|  |     state = state.copyWith(dataSavingMode: value); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   void setSoundEffects(bool value) { |   void setSoundEffects(bool value) { | ||||||
|     final prefs = ref.read(sharedPreferencesProvider); |     final prefs = ref.read(sharedPreferencesProvider); | ||||||
|     prefs.setBool(kAppSoundEffects, value); |     prefs.setBool(kAppSoundEffects, value); | ||||||
| @@ -127,6 +141,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier { | |||||||
|     ref.read(themeProvider.notifier).reloadTheme(); |     ref.read(themeProvider.notifier).reloadTheme(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void setShowBackgroundImage(bool value) { | ||||||
|  |     final prefs = ref.read(sharedPreferencesProvider); | ||||||
|  |     prefs.setBool(kAppShowBackgroundImage, value); | ||||||
|  |     state = state.copyWith(showBackgroundImage: value); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   void setCustomFonts(String? value) { |   void setCustomFonts(String? value) { | ||||||
|     final prefs = ref.read(sharedPreferencesProvider); |     final prefs = ref.read(sharedPreferencesProvider); | ||||||
|     prefs.setString(kAppCustomFonts, value ?? ''); |     prefs.setString(kAppCustomFonts, value ?? ''); | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ T _$identity<T>(T value) => value; | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$AppSettings { | mixin _$AppSettings { | ||||||
|  |  | ||||||
|  bool get autoTranslate; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get appBarTransparent; String? get customFonts; int? get appColorScheme;// The color stored via the int type |  bool get autoTranslate; bool get dataSavingMode; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get appBarTransparent; bool get showBackgroundImage; String? get customFonts; int? get appColorScheme;// The color stored via the int type | ||||||
|  Size? get windowSize; |  Size? get windowSize; | ||||||
| /// 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. | ||||||
| @@ -26,16 +26,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.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme,windowSize); | int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)'; |   return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -46,7 +46,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 autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme, Size? windowSize |  bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -63,13 +63,15 @@ 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? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) { | ||||||
|   return _then(_self.copyWith( |   return _then(_self.copyWith( | ||||||
| autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable | autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable | ||||||
|  | as bool,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 | ||||||
| as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable | as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable | as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable | as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable | ||||||
|  | as bool,showBackgroundImage: null == showBackgroundImage ? _self.showBackgroundImage : showBackgroundImage // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable | as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable | as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable | ||||||
| as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable | as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -155,10 +157,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate,  bool soundEffects,  bool aprilFoolFeatures,  bool enterToSend,  bool appBarTransparent,  String? customFonts,  int? appColorScheme,  Size? windowSize)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate,  bool dataSavingMode,  bool soundEffects,  bool aprilFoolFeatures,  bool enterToSend,  bool appBarTransparent,  bool showBackgroundImage,  String? customFonts,  int? appColorScheme,  Size? windowSize)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _AppSettings() when $default != null: | case _AppSettings() when $default != null: | ||||||
| return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.customFonts,_that.appColorScheme,_that.windowSize);case _: | return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -176,10 +178,10 @@ return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_ | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate,  bool soundEffects,  bool aprilFoolFeatures,  bool enterToSend,  bool appBarTransparent,  String? customFonts,  int? appColorScheme,  Size? windowSize)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate,  bool dataSavingMode,  bool soundEffects,  bool aprilFoolFeatures,  bool enterToSend,  bool appBarTransparent,  bool showBackgroundImage,  String? customFonts,  int? appColorScheme,  Size? windowSize)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _AppSettings(): | case _AppSettings(): | ||||||
| return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.customFonts,_that.appColorScheme,_that.windowSize);} | return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -193,10 +195,10 @@ return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_ | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate,  bool soundEffects,  bool aprilFoolFeatures,  bool enterToSend,  bool appBarTransparent,  String? customFonts,  int? appColorScheme,  Size? windowSize)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate,  bool dataSavingMode,  bool soundEffects,  bool aprilFoolFeatures,  bool enterToSend,  bool appBarTransparent,  bool showBackgroundImage,  String? customFonts,  int? appColorScheme,  Size? windowSize)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _AppSettings() when $default != null: | case _AppSettings() when $default != null: | ||||||
| return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.customFonts,_that.appColorScheme,_that.windowSize);case _: | return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -208,14 +210,16 @@ return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_ | |||||||
|  |  | ||||||
|  |  | ||||||
| class _AppSettings implements AppSettings { | class _AppSettings implements AppSettings { | ||||||
|   const _AppSettings({required this.autoTranslate, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.customFonts, required this.appColorScheme, required this.windowSize}); |   const _AppSettings({required this.autoTranslate, required this.dataSavingMode, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.windowSize}); | ||||||
|    |    | ||||||
|  |  | ||||||
| @override final  bool autoTranslate; | @override final  bool autoTranslate; | ||||||
|  | @override final  bool dataSavingMode; | ||||||
| @override final  bool soundEffects; | @override final  bool soundEffects; | ||||||
| @override final  bool aprilFoolFeatures; | @override final  bool aprilFoolFeatures; | ||||||
| @override final  bool enterToSend; | @override final  bool enterToSend; | ||||||
| @override final  bool appBarTransparent; | @override final  bool appBarTransparent; | ||||||
|  | @override final  bool showBackgroundImage; | ||||||
| @override final  String? customFonts; | @override final  String? customFonts; | ||||||
| @override final  int? appColorScheme; | @override final  int? appColorScheme; | ||||||
| // The color stored via the int type | // The color stored via the int type | ||||||
| @@ -231,16 +235,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.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)); |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @override | @override | ||||||
| int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme,windowSize); | int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)'; |   return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -251,7 +255,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 autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme, Size? windowSize |  bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -268,13 +272,15 @@ 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? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) { | ||||||
|   return _then(_AppSettings( |   return _then(_AppSettings( | ||||||
| autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable | autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable | ||||||
|  | as bool,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 | ||||||
| as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable | as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable | as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable | as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable | ||||||
|  | as bool,showBackgroundImage: null == showBackgroundImage ? _self.showBackgroundImage : showBackgroundImage // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable | as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable | ||||||
| as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable | as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable | ||||||
| as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable | as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ part of 'config.dart'; | |||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$appSettingsNotifierHash() => | String _$appSettingsNotifierHash() => | ||||||
|     r'c4f40a3bc4311c6360c2b5e44f8df5e5d7c1bd75'; |     r'cd18bff2614a94e3523634e6c577cefad0367eba'; | ||||||
|  |  | ||||||
| /// See also [AppSettingsNotifier]. | /// See also [AppSettingsNotifier]. | ||||||
| @ProviderFor(AppSettingsNotifier) | @ProviderFor(AppSettingsNotifier) | ||||||
|   | |||||||
| @@ -1,11 +1,9 @@ | |||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
| import 'dart:developer'; |  | ||||||
|  |  | ||||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | import 'package:freezed_annotation/freezed_annotation.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:flutter_langdetect/flutter_langdetect.dart' as langdetect; |  | ||||||
|  |  | ||||||
| part 'translate.freezed.dart'; | part 'translate.freezed.dart'; | ||||||
| part 'translate.g.dart'; | part 'translate.g.dart'; | ||||||
| @@ -29,10 +27,17 @@ Future<String> translateString(Ref ref, TranslateQuery query) async { | |||||||
|  |  | ||||||
| @riverpod | @riverpod | ||||||
| String? detectStringLanguage(Ref ref, String text) { | String? detectStringLanguage(Ref ref, String text) { | ||||||
|   try { |   bool isChinese(String text) { | ||||||
|     return langdetect.detectLangs(text).firstOrNull?.lang; |     final chineseRegex = RegExp(r'[\u4e00-\u9fff]'); | ||||||
|   } catch (err) { |     return chineseRegex.hasMatch(text); | ||||||
|     log('[Language] Unable to detect text\'s language: $text'); |   } | ||||||
|  |  | ||||||
|  |   bool isEnglish(String text) { | ||||||
|  |     final englishRegex = RegExp(r'[a-zA-Z]'); | ||||||
|  |     return englishRegex.hasMatch(text) && !isChinese(text); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (isChinese(text)) return "zh"; | ||||||
|  |   if (isEnglish(text)) return "en"; | ||||||
|   return null; |   return null; | ||||||
| } | } | ||||||
| } |  | ||||||
|   | |||||||
| @@ -149,7 +149,7 @@ class _TranslateStringProviderElement | |||||||
| } | } | ||||||
|  |  | ||||||
| String _$detectStringLanguageHash() => | String _$detectStringLanguageHash() => | ||||||
|     r'697b68464b3d00927cc43ccc1ba8ba93f2a470ed'; |     r'24fbf52edbbffcc8dc4f09f7206f82d69728e703'; | ||||||
|  |  | ||||||
| /// See also [detectStringLanguage]. | /// See also [detectStringLanguage]. | ||||||
| @ProviderFor(detectStringLanguage) | @ProviderFor(detectStringLanguage) | ||||||
|   | |||||||
| @@ -1,9 +1,15 @@ | |||||||
|  | import 'dart:convert'; | ||||||
| import 'dart:developer'; | import 'dart:developer'; | ||||||
|  | import 'dart:io' show Platform; | ||||||
|  |  | ||||||
|  | import 'package:dio/dio.dart'; | ||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
| import 'package:firebase_analytics/firebase_analytics.dart'; | import 'package:firebase_analytics/firebase_analytics.dart'; | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
|  | import 'package:flutter_platform_alert/flutter_platform_alert.dart'; | ||||||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
| import 'package:island/pods/config.dart'; | import 'package:island/pods/config.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
|  |  | ||||||
| @@ -13,13 +19,59 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> { | |||||||
|   UserInfoNotifier(this._ref) : super(const AsyncValue.data(null)); |   UserInfoNotifier(this._ref) : super(const AsyncValue.data(null)); | ||||||
|  |  | ||||||
|   Future<void> fetchUser() async { |   Future<void> fetchUser() async { | ||||||
|  |     final token = _ref.watch(tokenProvider); | ||||||
|  |     if (token == null) { | ||||||
|  |       log('[UserInfo] No token found, not going to fetch...'); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     try { |     try { | ||||||
|       final client = _ref.read(apiClientProvider); |       final client = _ref.read(apiClientProvider); | ||||||
|       final response = await client.get('/id/accounts/me'); |       final response = await client.get('/id/accounts/me'); | ||||||
|       final user = SnAccount.fromJson(response.data); |       final user = SnAccount.fromJson(response.data); | ||||||
|       state = AsyncValue.data(user); |       state = AsyncValue.data(user); | ||||||
|  |  | ||||||
|  |       if (kIsWeb || !Platform.isLinux) { | ||||||
|         FirebaseAnalytics.instance.setUserId(id: user.id); |         FirebaseAnalytics.instance.setUserId(id: user.id); | ||||||
|  |       } | ||||||
|     } catch (error, stackTrace) { |     } catch (error, stackTrace) { | ||||||
|  |       if (!kIsWeb) { | ||||||
|  |         if (error is DioException) { | ||||||
|  |           FlutterPlatformAlert.showCustomAlert( | ||||||
|  |             windowTitle: 'failedToLoadUserInfo'.tr(), | ||||||
|  |             text: [ | ||||||
|  |               (error.response?.statusCode == 401 | ||||||
|  |                       ? 'failedToLoadUserInfoUnauthorized' | ||||||
|  |                       : 'failedToLoadUserInfoNetwork') | ||||||
|  |                   .tr() | ||||||
|  |                   .trim(), | ||||||
|  |               '${error.response!.statusCode}\n${error.response?.headers}', | ||||||
|  |               jsonEncode(error.response?.data), | ||||||
|  |             ].join('\n\n'), | ||||||
|  |             iconStyle: IconStyle.error, | ||||||
|  |             neutralButtonTitle: 'retry'.tr(), | ||||||
|  |             negativeButtonTitle: 'okay'.tr(), | ||||||
|  |           ).then((value) { | ||||||
|  |             if (value == CustomButton.neutralButton) { | ||||||
|  |               fetchUser(); | ||||||
|  |             } | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |         FlutterPlatformAlert.showCustomAlert( | ||||||
|  |           windowTitle: 'failedToLoadUserInfo'.tr(), | ||||||
|  |           text: | ||||||
|  |               [ | ||||||
|  |                 'failedToLoadUserInfoNetwork'.tr(), | ||||||
|  |                 error.toString(), | ||||||
|  |               ].join('\n\n').trim(), | ||||||
|  |           iconStyle: IconStyle.error, | ||||||
|  |           neutralButtonTitle: 'retry'.tr(), | ||||||
|  |           negativeButtonTitle: 'okay'.tr(), | ||||||
|  |         ).then((value) { | ||||||
|  |           if (value == CustomButton.neutralButton) { | ||||||
|  |             fetchUser(); | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|       log( |       log( | ||||||
|         "[UserInfo] Failed to fetch user info...", |         "[UserInfo] Failed to fetch user info...", | ||||||
|         name: 'UserInfoNotifier', |         name: 'UserInfoNotifier', | ||||||
| @@ -35,9 +87,11 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> { | |||||||
|     final prefs = _ref.read(sharedPreferencesProvider); |     final prefs = _ref.read(sharedPreferencesProvider); | ||||||
|     await prefs.remove(kTokenPairStoreKey); |     await prefs.remove(kTokenPairStoreKey); | ||||||
|     _ref.invalidate(tokenProvider); |     _ref.invalidate(tokenProvider); | ||||||
|  |     if (kIsWeb || !Platform.isLinux) { | ||||||
|       FirebaseAnalytics.instance.setUserId(id: null); |       FirebaseAnalytics.instance.setUserId(id: null); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| final userInfoProvider = | final userInfoProvider = | ||||||
|     StateNotifierProvider<UserInfoNotifier, AsyncValue<SnAccount?>>( |     StateNotifierProvider<UserInfoNotifier, AsyncValue<SnAccount?>>( | ||||||
|   | |||||||
							
								
								
									
										212
									
								
								lib/route.dart
									
									
									
									
									
								
							
							
						
						
									
										212
									
								
								lib/route.dart
									
									
									
									
									
								
							| @@ -1,14 +1,25 @@ | |||||||
|  | import 'dart:io' show Platform; | ||||||
|  | import 'package:animations/animations.dart'; | ||||||
| import 'package:firebase_analytics/firebase_analytics.dart'; | import 'package:firebase_analytics/firebase_analytics.dart'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter/foundation.dart' show kIsWeb; | ||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/screens/about.dart'; | import 'package:island/screens/about.dart'; | ||||||
| import 'package:island/screens/developers/apps.dart'; | import 'package:island/screens/account/credits.dart'; | ||||||
|  | import 'package:island/screens/developers/app_detail.dart'; | ||||||
|  | import 'package:island/screens/developers/bot_detail.dart'; | ||||||
| import 'package:island/screens/developers/edit_app.dart'; | import 'package:island/screens/developers/edit_app.dart'; | ||||||
|  | import 'package:island/screens/developers/edit_bot.dart'; | ||||||
| import 'package:island/screens/developers/new_app.dart'; | import 'package:island/screens/developers/new_app.dart'; | ||||||
| import 'package:island/screens/developers/hub.dart'; | import 'package:island/screens/developers/hub.dart'; | ||||||
|  | import 'package:island/screens/developers/new_bot.dart'; | ||||||
|  | import 'package:island/screens/developers/projects.dart'; | ||||||
|  | import 'package:island/screens/developers/edit_project.dart'; | ||||||
|  | import 'package:island/screens/developers/new_project.dart'; | ||||||
|  | import 'package:island/screens/developers/project_detail.dart'; | ||||||
| import 'package:island/screens/discovery/articles.dart'; | import 'package:island/screens/discovery/articles.dart'; | ||||||
|  | import 'package:island/screens/posts/post_categories_list.dart'; | ||||||
| import 'package:island/screens/posts/post_category_detail.dart'; | import 'package:island/screens/posts/post_category_detail.dart'; | ||||||
| import 'package:island/screens/posts/post_search.dart'; | import 'package:island/screens/posts/post_search.dart'; | ||||||
| import 'package:island/widgets/app_wrapper.dart'; | import 'package:island/widgets/app_wrapper.dart'; | ||||||
| @@ -20,19 +31,22 @@ import 'package:island/screens/notification.dart'; | |||||||
| import 'package:island/screens/wallet.dart'; | import 'package:island/screens/wallet.dart'; | ||||||
| import 'package:island/screens/account/relationship.dart'; | import 'package:island/screens/account/relationship.dart'; | ||||||
| import 'package:island/screens/account/profile.dart'; | import 'package:island/screens/account/profile.dart'; | ||||||
| import 'package:island/screens/account/me/update.dart'; | import 'package:island/screens/account/me/profile_update.dart'; | ||||||
| import 'package:island/screens/account/leveling.dart'; | import 'package:island/screens/account/leveling.dart'; | ||||||
| import 'package:island/screens/account/me/settings.dart'; | import 'package:island/screens/account/me/account_settings.dart'; | ||||||
| import 'package:island/screens/chat/chat.dart'; | import 'package:island/screens/chat/chat.dart'; | ||||||
| import 'package:island/screens/chat/room.dart'; | import 'package:island/screens/chat/room.dart'; | ||||||
| import 'package:island/screens/chat/room_detail.dart'; | import 'package:island/screens/chat/room_detail.dart'; | ||||||
| import 'package:island/screens/chat/call.dart'; | import 'package:island/screens/chat/call.dart'; | ||||||
|  | import 'package:island/screens/chat/search_messages_screen.dart'; | ||||||
| import 'package:island/screens/creators/hub.dart'; | import 'package:island/screens/creators/hub.dart'; | ||||||
| import 'package:island/screens/creators/posts/post_manage_list.dart'; | import 'package:island/screens/creators/posts/post_manage_list.dart'; | ||||||
| import 'package:island/screens/creators/stickers/stickers.dart'; | import 'package:island/screens/creators/stickers/stickers.dart'; | ||||||
| import 'package:island/screens/creators/stickers/pack_detail.dart'; | import 'package:island/screens/creators/stickers/pack_detail.dart'; | ||||||
| import 'package:island/screens/stickers/marketplace.dart'; | import 'package:island/screens/stickers/sticker_marketplace.dart'; | ||||||
| import 'package:island/screens/stickers/pack_detail.dart'; | import 'package:island/screens/stickers/pack_detail.dart'; | ||||||
|  | import 'package:island/screens/discovery/feeds/feed_marketplace.dart'; | ||||||
|  | import 'package:island/screens/discovery/feeds/feed_detail.dart'; | ||||||
| import 'package:island/screens/creators/poll/poll_list.dart'; | import 'package:island/screens/creators/poll/poll_list.dart'; | ||||||
| import 'package:island/screens/creators/publishers.dart'; | import 'package:island/screens/creators/publishers.dart'; | ||||||
| import 'package:island/screens/creators/webfeed/webfeed_list.dart'; | import 'package:island/screens/creators/webfeed/webfeed_list.dart'; | ||||||
| @@ -50,18 +64,41 @@ import 'package:island/screens/account/event_calendar.dart'; | |||||||
| import 'package:island/screens/discovery/realms.dart'; | import 'package:island/screens/discovery/realms.dart'; | ||||||
| import 'package:island/screens/reports/report_detail.dart'; | import 'package:island/screens/reports/report_detail.dart'; | ||||||
| import 'package:island/screens/reports/report_list.dart'; | import 'package:island/screens/reports/report_list.dart'; | ||||||
|  | import 'package:island/widgets/post/post_shuffle.dart'; | ||||||
|  |  | ||||||
| // Shell route keys for nested navigation | // Shell route keys for nested navigation | ||||||
| final rootNavigatorKey = GlobalKey<NavigatorState>(); | final rootNavigatorKey = GlobalKey<NavigatorState>(); | ||||||
| final _shellNavigatorKey = GlobalKey<NavigatorState>(); | final _shellNavigatorKey = GlobalKey<NavigatorState>(); | ||||||
| final _tabsShellKey = GlobalKey<NavigatorState>(); | final _tabsShellKey = GlobalKey<NavigatorState>(); | ||||||
|  |  | ||||||
|  | Widget _tabPagesTransitionBuilder( | ||||||
|  |   BuildContext context, | ||||||
|  |   Animation<double> animation, | ||||||
|  |   Animation<double> secondaryAnimation, | ||||||
|  |   Widget child, | ||||||
|  | ) { | ||||||
|  |   return FadeThroughTransition( | ||||||
|  |     animation: animation, | ||||||
|  |     secondaryAnimation: secondaryAnimation, | ||||||
|  |     fillColor: Theme.of(context).colorScheme.surface, | ||||||
|  |     child: child, | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool get _supportsAnalytics => | ||||||
|  |     kIsWeb || | ||||||
|  |     Platform.isAndroid || | ||||||
|  |     Platform.isIOS || | ||||||
|  |     Platform.isMacOS || | ||||||
|  |     Platform.isWindows; | ||||||
|  |  | ||||||
| // Provider for the router | // Provider for the router | ||||||
| final routerProvider = Provider<GoRouter>((ref) { | final routerProvider = Provider<GoRouter>((ref) { | ||||||
|   return GoRouter( |   return GoRouter( | ||||||
|     navigatorKey: rootNavigatorKey, |     navigatorKey: rootNavigatorKey, | ||||||
|     initialLocation: '/', |     initialLocation: '/', | ||||||
|     observers: [ |     observers: [ | ||||||
|  |       if (_supportsAnalytics) | ||||||
|         FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance), |         FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance), | ||||||
|     ], |     ], | ||||||
|     routes: [ |     routes: [ | ||||||
| @@ -262,30 +299,99 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|                 builder: (context, state) => const DeveloperHubScreen(), |                 builder: (context, state) => const DeveloperHubScreen(), | ||||||
|               ), |               ), | ||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'developerApps', |                 name: 'developerProjects', | ||||||
|                 path: '/developers/:name/apps', |                 path: '/developers/:name/projects', | ||||||
|                 builder: |                 builder: | ||||||
|                     (context, state) => CustomAppsScreen( |                     (context, state) => DevProjectsScreen( | ||||||
|                       publisherName: state.pathParameters['name']!, |                       publisherName: state.pathParameters['name']!, | ||||||
|                     ), |                     ), | ||||||
|               ), |               ), | ||||||
|  |               GoRoute( | ||||||
|  |                 name: 'developerProjectNew', | ||||||
|  |                 path: '/developers/:name/projects/new', | ||||||
|  |                 builder: | ||||||
|  |                     (context, state) => NewProjectScreen( | ||||||
|  |                       publisherName: state.pathParameters['name']!, | ||||||
|  |                     ), | ||||||
|  |               ), | ||||||
|  |               GoRoute( | ||||||
|  |                 name: 'developerProjectEdit', | ||||||
|  |                 path: '/developers/:name/projects/:id/edit', | ||||||
|  |                 builder: | ||||||
|  |                     (context, state) => EditProjectScreen( | ||||||
|  |                       publisherName: state.pathParameters['name']!, | ||||||
|  |                       id: state.pathParameters['id']!, | ||||||
|  |                     ), | ||||||
|  |               ), | ||||||
|  |               GoRoute( | ||||||
|  |                 name: 'developerProjectDetail', | ||||||
|  |                 path: '/developers/:name/projects/:projectId', | ||||||
|  |                 builder: | ||||||
|  |                     (context, state) => ProjectDetailScreen( | ||||||
|  |                       publisherName: state.pathParameters['name']!, | ||||||
|  |                       projectId: state.pathParameters['projectId']!, | ||||||
|  |                     ), | ||||||
|  |                 routes: [ | ||||||
|                   GoRoute( |                   GoRoute( | ||||||
|                     name: 'developerAppNew', |                     name: 'developerAppNew', | ||||||
|                 path: '/developers/:name/apps/new', |                     path: 'apps/new', | ||||||
|                     builder: |                     builder: | ||||||
|                         (context, state) => NewCustomAppScreen( |                         (context, state) => NewCustomAppScreen( | ||||||
|                           publisherName: state.pathParameters['name']!, |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|                         ), |                         ), | ||||||
|                   ), |                   ), | ||||||
|                   GoRoute( |                   GoRoute( | ||||||
|                     name: 'developerAppEdit', |                     name: 'developerAppEdit', | ||||||
|                 path: '/developers/:name/apps/:id', |                     path: 'apps/:id/edit', | ||||||
|                     builder: |                     builder: | ||||||
|                         (context, state) => EditAppScreen( |                         (context, state) => EditAppScreen( | ||||||
|                           publisherName: state.pathParameters['name']!, |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|                           id: state.pathParameters['id']!, |                           id: state.pathParameters['id']!, | ||||||
|                         ), |                         ), | ||||||
|                   ), |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'developerAppDetail', | ||||||
|  |                     path: 'apps/:appId', | ||||||
|  |                     builder: | ||||||
|  |                         (context, state) => AppDetailScreen( | ||||||
|  |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|  |                           appId: state.pathParameters['appId']!, | ||||||
|  |                         ), | ||||||
|  |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'developerBotDetail', | ||||||
|  |                     path: 'bots/:botId', | ||||||
|  |                     builder: | ||||||
|  |                         (context, state) => BotDetailScreen( | ||||||
|  |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|  |                           botId: state.pathParameters['botId']!, | ||||||
|  |                         ), | ||||||
|  |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'developerBotNew', | ||||||
|  |                     path: 'bots/new', | ||||||
|  |                     builder: | ||||||
|  |                         (context, state) => NewBotScreen( | ||||||
|  |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|  |                         ), | ||||||
|  |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'developerBotEdit', | ||||||
|  |                     path: 'bots/:id/edit', | ||||||
|  |                     builder: | ||||||
|  |                         (context, state) => EditBotScreen( | ||||||
|  |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|  |                           id: state.pathParameters['id']!, | ||||||
|  |                         ), | ||||||
|  |                   ), | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|  |  | ||||||
| @@ -339,7 +445,12 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'explore', |                 name: 'explore', | ||||||
|                 path: '/', |                 path: '/', | ||||||
|                 builder: (context, state) => const ExploreScreen(), |                 pageBuilder: | ||||||
|  |                     (context, state) => CustomTransitionPage( | ||||||
|  |                       key: const ValueKey('explore'), | ||||||
|  |                       child: const ExploreScreen(), | ||||||
|  |                       transitionsBuilder: _tabPagesTransitionBuilder, | ||||||
|  |                     ), | ||||||
|               ), |               ), | ||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'postSearch', |                 name: 'postSearch', | ||||||
| @@ -347,12 +458,14 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|                 builder: (context, state) => const PostSearchScreen(), |                 builder: (context, state) => const PostSearchScreen(), | ||||||
|               ), |               ), | ||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'postDetail', |                 name: 'postShuffle', | ||||||
|                 path: '/posts/:id', |                 path: '/posts/shuffle', | ||||||
|                 builder: (context, state) { |                 builder: (context, state) => const PostShuffleScreen(), | ||||||
|                   final id = state.pathParameters['id']!; |               ), | ||||||
|                   return PostDetailScreen(id: id); |               GoRoute( | ||||||
|                 }, |                 name: 'postCategories', | ||||||
|  |                 path: '/posts/categories', | ||||||
|  |                 builder: (context, state) => const PostCategoriesListScreen(), | ||||||
|               ), |               ), | ||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'postCategoryDetail', |                 name: 'postCategoryDetail', | ||||||
| @@ -362,6 +475,11 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|                   return PostCategoryDetailScreen(slug: slug, isCategory: true); |                   return PostCategoryDetailScreen(slug: slug, isCategory: true); | ||||||
|                 }, |                 }, | ||||||
|               ), |               ), | ||||||
|  |               GoRoute( | ||||||
|  |                 name: 'postTags', | ||||||
|  |                 path: '/posts/tags', | ||||||
|  |                 builder: (context, state) => const PostTagsListScreen(), | ||||||
|  |               ), | ||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'postTagDetail', |                 name: 'postTagDetail', | ||||||
|                 path: '/posts/tags/:slug', |                 path: '/posts/tags/:slug', | ||||||
| @@ -373,6 +491,14 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|                   ); |                   ); | ||||||
|                 }, |                 }, | ||||||
|               ), |               ), | ||||||
|  |               GoRoute( | ||||||
|  |                 name: 'postDetail', | ||||||
|  |                 path: '/posts/:id', | ||||||
|  |                 builder: (context, state) { | ||||||
|  |                   final id = state.pathParameters['id']!; | ||||||
|  |                   return PostDetailScreen(id: id); | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'publisherProfile', |                 name: 'publisherProfile', | ||||||
|                 path: '/publishers/:name', |                 path: '/publishers/:name', | ||||||
| @@ -389,8 +515,12 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|  |  | ||||||
|               // Chat tab |               // Chat tab | ||||||
|               ShellRoute( |               ShellRoute( | ||||||
|                 builder: |                 pageBuilder: | ||||||
|                     (context, state, child) => ChatShellScreen(child: child), |                     (context, state, child) => CustomTransitionPage( | ||||||
|  |                       key: const ValueKey('chat'), | ||||||
|  |                       child: ChatShellScreen(child: child), | ||||||
|  |                       transitionsBuilder: _tabPagesTransitionBuilder, | ||||||
|  |                     ), | ||||||
|                 routes: [ |                 routes: [ | ||||||
|                   GoRoute( |                   GoRoute( | ||||||
|                     name: 'chatList', |                     name: 'chatList', | ||||||
| @@ -426,6 +556,14 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|                       return ChatDetailScreen(id: id); |                       return ChatDetailScreen(id: id); | ||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'searchMessages', | ||||||
|  |                     path: '/chat/:id/search', | ||||||
|  |                     builder: (context, state) { | ||||||
|  |                       final id = state.pathParameters['id']!; | ||||||
|  |                       return SearchMessagesScreen(roomId: id); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|  |  | ||||||
| @@ -433,7 +571,12 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'realmList', |                 name: 'realmList', | ||||||
|                 path: '/realms', |                 path: '/realms', | ||||||
|                 builder: (context, state) => const RealmListScreen(), |                 pageBuilder: | ||||||
|  |                     (context, state) => CustomTransitionPage( | ||||||
|  |                       key: const ValueKey('realms'), | ||||||
|  |                       child: const RealmListScreen(), | ||||||
|  |                       transitionsBuilder: _tabPagesTransitionBuilder, | ||||||
|  |                     ), | ||||||
|                 routes: [ |                 routes: [ | ||||||
|                   GoRoute( |                   GoRoute( | ||||||
|                     name: 'realmNew', |                     name: 'realmNew', | ||||||
| @@ -461,8 +604,12 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|  |  | ||||||
|               // Account tab |               // Account tab | ||||||
|               ShellRoute( |               ShellRoute( | ||||||
|                 builder: |                 pageBuilder: | ||||||
|                     (context, state, child) => AccountShellScreen(child: child), |                     (context, state, child) => CustomTransitionPage( | ||||||
|  |                       key: const ValueKey('account'), | ||||||
|  |                       child: AccountShellScreen(child: child), | ||||||
|  |                       transitionsBuilder: _tabPagesTransitionBuilder, | ||||||
|  |                     ), | ||||||
|                 routes: [ |                 routes: [ | ||||||
|                   GoRoute( |                   GoRoute( | ||||||
|                     name: 'account', |                     name: 'account', | ||||||
| @@ -486,6 +633,22 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|                       ), |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ), |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'webFeedMarketplace', | ||||||
|  |                     path: '/feeds', | ||||||
|  |                     builder: | ||||||
|  |                         (context, state) => const MarketplaceWebFeedsScreen(), | ||||||
|  |                     routes: [ | ||||||
|  |                       GoRoute( | ||||||
|  |                         name: 'webFeedDetail', | ||||||
|  |                         path: ':feedId', | ||||||
|  |                         builder: (context, state) { | ||||||
|  |                           final feedId = state.pathParameters['feedId']!; | ||||||
|  |                           return MarketplaceWebFeedDetailScreen(id: feedId); | ||||||
|  |                         }, | ||||||
|  |                       ), | ||||||
|  |                     ], | ||||||
|  |                   ), | ||||||
|                   GoRoute( |                   GoRoute( | ||||||
|                     name: 'notifications', |                     name: 'notifications', | ||||||
|                     path: '/account/notifications', |                     path: '/account/notifications', | ||||||
| @@ -496,6 +659,11 @@ final routerProvider = Provider<GoRouter>((ref) { | |||||||
|                     path: '/account/wallet', |                     path: '/account/wallet', | ||||||
|                     builder: (context, state) => const WalletScreen(), |                     builder: (context, state) => const WalletScreen(), | ||||||
|                   ), |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'socialCredits', | ||||||
|  |                     path: '/account/credits', | ||||||
|  |                     builder: (context, state) => const SocialCreditsScreen(), | ||||||
|  |                   ), | ||||||
|                   GoRoute( |                   GoRoute( | ||||||
|                     name: 'relationships', |                     name: 'relationships', | ||||||
|                     path: '/account/relationships', |                     path: '/account/relationships', | ||||||
|   | |||||||
| @@ -178,7 +178,8 @@ class _AboutScreenState extends ConsumerState<AboutScreen> { | |||||||
|                                 context, |                                 context, | ||||||
|                                 icon: Symbols.label, |                                 icon: Symbols.label, | ||||||
|                                 label: 'aboutDeviceName'.tr(), |                                 label: 'aboutDeviceName'.tr(), | ||||||
|                                 value: _deviceInfo?.data['name'], |                                 value: | ||||||
|  |                                     _deviceInfo?.data['name'] ?? 'unknown'.tr(), | ||||||
|                               ), |                               ), | ||||||
|                               _buildInfoItem( |                               _buildInfoItem( | ||||||
|                                 context, |                                 context, | ||||||
|   | |||||||
| @@ -3,12 +3,14 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:gap/gap.dart'; | import 'package:gap/gap.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/pods/userinfo.dart'; | import 'package:island/pods/userinfo.dart'; | ||||||
| import 'package:island/screens/notification.dart'; | import 'package:island/screens/notification.dart'; | ||||||
| import 'package:island/services/responsive.dart'; | import 'package:island/services/responsive.dart'; | ||||||
| import 'package:island/widgets/account/account_name.dart'; | import 'package:island/widgets/account/account_name.dart'; | ||||||
| import 'package:island/widgets/account/status.dart'; | import 'package:island/widgets/account/status.dart'; | ||||||
| import 'package:island/widgets/account/leveling_progress.dart'; | import 'package:island/widgets/account/leveling_progress.dart'; | ||||||
|  | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/content/cloud_files.dart'; | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
| import 'package:island/widgets/debug_sheet.dart'; | import 'package:island/widgets/debug_sheet.dart'; | ||||||
| @@ -66,6 +68,7 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|       body: SingleChildScrollView( |       body: SingleChildScrollView( | ||||||
|         padding: getTabbedPadding(context), |         padding: getTabbedPadding(context), | ||||||
|         child: Column( |         child: Column( | ||||||
|  |           spacing: 4, | ||||||
|           children: <Widget>[ |           children: <Widget>[ | ||||||
|             Card( |             Card( | ||||||
|               child: Column( |               child: Column( | ||||||
| @@ -110,20 +113,22 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                               crossAxisAlignment: CrossAxisAlignment.baseline, |                               crossAxisAlignment: CrossAxisAlignment.baseline, | ||||||
|                               textBaseline: TextBaseline.alphabetic, |                               textBaseline: TextBaseline.alphabetic, | ||||||
|                               children: [ |                               children: [ | ||||||
|                                 AccountName( |                                 Flexible( | ||||||
|  |                                   child: AccountName( | ||||||
|                                     account: user.value!, |                                     account: user.value!, | ||||||
|                                     style: TextStyle( |                                     style: TextStyle( | ||||||
|                                       fontSize: 16, |                                       fontSize: 16, | ||||||
|                                       fontWeight: FontWeight.bold, |                                       fontWeight: FontWeight.bold, | ||||||
|                                     ), |                                     ), | ||||||
|                                   ), |                                   ), | ||||||
|                                 Text('@${user.value!.name}'), |                                 ), | ||||||
|  |                                 Flexible(child: Text('@${user.value!.name}')), | ||||||
|                               ], |                               ], | ||||||
|                             ), |                             ), | ||||||
|                             Text( |                             Text( | ||||||
|                               (user.value!.profile.bio.isNotEmpty) |                               (user.value!.profile.bio.isNotEmpty) | ||||||
|                                   ? user.value!.profile.bio |                                   ? user.value!.profile.bio | ||||||
|                                   : 'No description yet.', |                                   : 'descriptionNone'.tr(), | ||||||
|                               maxLines: 1, |                               maxLines: 1, | ||||||
|                               overflow: TextOverflow.ellipsis, |                               overflow: TextOverflow.ellipsis, | ||||||
|                             ), |                             ), | ||||||
| @@ -156,8 +161,16 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                         crossAxisAlignment: CrossAxisAlignment.start, |                         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                         children: [ |                         children: [ | ||||||
|                           Icon(Symbols.draw, size: 28).padding(bottom: 8), |                           Icon(Symbols.draw, size: 28).padding(bottom: 8), | ||||||
|                           Text('creatorHub').tr().fontSize(16).bold(), |                           Text( | ||||||
|                           Text('creatorHubDescription').tr(), |                             'creatorHub', | ||||||
|  |                             maxLines: 1, | ||||||
|  |                             overflow: TextOverflow.ellipsis, | ||||||
|  |                           ).tr().fontSize(16).bold(), | ||||||
|  |                           Text( | ||||||
|  |                             'creatorHubDescription', | ||||||
|  |                             maxLines: 2, | ||||||
|  |                             overflow: TextOverflow.ellipsis, | ||||||
|  |                           ).tr(), | ||||||
|                         ], |                         ], | ||||||
|                       ).padding(horizontal: 16, vertical: 12), |                       ).padding(horizontal: 16, vertical: 12), | ||||||
|                       onTap: () { |                       onTap: () { | ||||||
| @@ -174,8 +187,16 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                         crossAxisAlignment: CrossAxisAlignment.start, |                         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                         children: [ |                         children: [ | ||||||
|                           Icon(Symbols.code, size: 28).padding(bottom: 8), |                           Icon(Symbols.code, size: 28).padding(bottom: 8), | ||||||
|                           Text('developerPortal').tr().fontSize(16).bold(), |                           Text( | ||||||
|                           Text('developerPortalDescription').tr(), |                             'developerPortal', | ||||||
|  |                             maxLines: 1, | ||||||
|  |                             overflow: TextOverflow.ellipsis, | ||||||
|  |                           ).tr().fontSize(16).bold(), | ||||||
|  |                           Text( | ||||||
|  |                             'developerPortalDescription', | ||||||
|  |                             maxLines: 2, | ||||||
|  |                             overflow: TextOverflow.ellipsis, | ||||||
|  |                           ).tr(), | ||||||
|                         ], |                         ], | ||||||
|                       ).padding(horizontal: 16, vertical: 12), |                       ).padding(horizontal: 16, vertical: 12), | ||||||
|                       onTap: () { |                       onTap: () { | ||||||
| @@ -234,6 +255,26 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                 context.pushNamed('stickerMarketplace'); |                 context.pushNamed('stickerMarketplace'); | ||||||
|               }, |               }, | ||||||
|             ), |             ), | ||||||
|  |             ListTile( | ||||||
|  |               minTileHeight: 48, | ||||||
|  |               leading: const Icon(Symbols.rss_feed), | ||||||
|  |               trailing: const Icon(Symbols.chevron_right), | ||||||
|  |               contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |               title: Text('webFeeds').tr(), | ||||||
|  |               onTap: () { | ||||||
|  |                 context.pushNamed('webFeedMarketplace'); | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|  |             ListTile( | ||||||
|  |               minTileHeight: 48, | ||||||
|  |               leading: const Icon(Symbols.star), | ||||||
|  |               trailing: const Icon(Symbols.chevron_right), | ||||||
|  |               contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |               title: Text('credits').tr(), | ||||||
|  |               onTap: () { | ||||||
|  |                 context.pushNamed('socialCredits'); | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|             ListTile( |             ListTile( | ||||||
|               minTileHeight: 48, |               minTileHeight: 48, | ||||||
|               title: Text('abuseReport').tr(), |               title: Text('abuseReport').tr(), | ||||||
| @@ -303,7 +344,12 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|               trailing: const Icon(Symbols.chevron_right), |               trailing: const Icon(Symbols.chevron_right), | ||||||
|               contentPadding: EdgeInsets.symmetric(horizontal: 24), |               contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|               title: Text('logout').tr(), |               title: Text('logout').tr(), | ||||||
|               onTap: () { |               onTap: () async { | ||||||
|  |                 final apiClient = ref.watch(apiClientProvider); | ||||||
|  |                 showLoadingModal(context); | ||||||
|  |                 await apiClient.delete('/id/accounts/me/sessions/current'); | ||||||
|  |                 if (!context.mounted) return; | ||||||
|  |                 hideLoadingModal(context); | ||||||
|                 final userNotifier = ref.read(userInfoProvider.notifier); |                 final userNotifier = ref.read(userInfoProvider.notifier); | ||||||
|                 userNotifier.logOut(); |                 userNotifier.logOut(); | ||||||
|               }, |               }, | ||||||
| @@ -382,6 +428,15 @@ class _UnauthorizedAccountScreen extends StatelessWidget { | |||||||
|                       }, |                       }, | ||||||
|                       child: Text('about').tr(), |                       child: Text('about').tr(), | ||||||
|                     ), |                     ), | ||||||
|  |                     TextButton( | ||||||
|  |                       child: Text('debugOptions').tr(), | ||||||
|  |                       onPressed: () { | ||||||
|  |                         showModalBottomSheet( | ||||||
|  |                           context: context, | ||||||
|  |                           builder: (context) => DebugSheet(), | ||||||
|  |                         ); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|                     TextButton( |                     TextButton( | ||||||
|                       onPressed: () { |                       onPressed: () { | ||||||
|                         context.pushNamed('settings'); |                         context.pushNamed('settings'); | ||||||
|   | |||||||
							
								
								
									
										152
									
								
								lib/screens/account/credits.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								lib/screens/account/credits.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | |||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:gap/gap.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/account.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|  | import 'package:material_symbols_icons/material_symbols_icons.dart'; | ||||||
|  | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  | import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||||
|  | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
|  | part 'credits.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<double> socialCredits(Ref ref) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final response = await client.get('/id/accounts/me/credits'); | ||||||
|  |   if (response.statusCode != 200) { | ||||||
|  |     throw Exception('Failed to load social credits'); | ||||||
|  |   } | ||||||
|  |   return response.data?.toDouble() ?? 0.0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | class SocialCreditHistoryNotifier extends _$SocialCreditHistoryNotifier | ||||||
|  |     with CursorPagingNotifierMixin<SnSocialCreditRecord> { | ||||||
|  |   static const int _pageSize = 20; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<CursorPagingData<SnSocialCreditRecord>> build() => fetch(cursor: null); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<CursorPagingData<SnSocialCreditRecord>> fetch({ | ||||||
|  |     required String? cursor, | ||||||
|  |   }) async { | ||||||
|  |     final client = ref.read(apiClientProvider); | ||||||
|  |     final offset = cursor == null ? 0 : int.parse(cursor); | ||||||
|  |  | ||||||
|  |     final queryParams = {'offset': offset, 'take': _pageSize}; | ||||||
|  |  | ||||||
|  |     final response = await client.get( | ||||||
|  |       '/id/accounts/me/credits/history', | ||||||
|  |       queryParameters: queryParams, | ||||||
|  |     ); | ||||||
|  |     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||||
|  |     final List<dynamic> data = response.data; | ||||||
|  |     final records = | ||||||
|  |         data.map((json) => SnSocialCreditRecord.fromJson(json)).toList(); | ||||||
|  |  | ||||||
|  |     final hasMore = offset + records.length < total; | ||||||
|  |     final nextCursor = hasMore ? (offset + records.length).toString() : null; | ||||||
|  |  | ||||||
|  |     return CursorPagingData( | ||||||
|  |       items: records, | ||||||
|  |       hasMore: hasMore, | ||||||
|  |       nextCursor: nextCursor, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class SocialCreditsScreen extends HookConsumerWidget { | ||||||
|  |   const SocialCreditsScreen({super.key}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final socialCredits = ref.watch(socialCreditsProvider); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar(title: Text('socialCredits').tr()), | ||||||
|  |       body: Column( | ||||||
|  |         children: [ | ||||||
|  |           Card( | ||||||
|  |             margin: EdgeInsets.only(left: 16, right: 16, top: 8), | ||||||
|  |             child: socialCredits | ||||||
|  |                 .when( | ||||||
|  |                   data: | ||||||
|  |                       (credits) => Stack( | ||||||
|  |                         children: [ | ||||||
|  |                           Column( | ||||||
|  |                             crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                             children: [ | ||||||
|  |                               Text( | ||||||
|  |                                 credits < 100 | ||||||
|  |                                     ? 'socialCreditsLevelPoor'.tr() | ||||||
|  |                                     : credits < 150 | ||||||
|  |                                     ? 'socialCreditsLevelNormal'.tr() | ||||||
|  |                                     : credits < 200 | ||||||
|  |                                     ? 'socialCreditsLevelGood'.tr() | ||||||
|  |                                     : 'socialCreditsLevelExcellent'.tr(), | ||||||
|  |                               ).tr().bold().fontSize(20), | ||||||
|  |                               Text( | ||||||
|  |                                 '${credits.toStringAsFixed(2)} pts', | ||||||
|  |                               ).fontSize(14), | ||||||
|  |                               const Gap(8), | ||||||
|  |                               LinearProgressIndicator(value: credits / 200), | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                           Positioned( | ||||||
|  |                             right: 0, | ||||||
|  |                             top: 0, | ||||||
|  |                             child: IconButton( | ||||||
|  |                               onPressed: () {}, | ||||||
|  |                               icon: const Icon(Symbols.info), | ||||||
|  |                               tooltip: 'socialCreditsDescription'.tr(), | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                   error: (_, _) => Text('Error loading credits'), | ||||||
|  |                   loading: () => const LinearProgressIndicator(), | ||||||
|  |                 ) | ||||||
|  |                 .padding(horizontal: 20, vertical: 16), | ||||||
|  |           ), | ||||||
|  |           Expanded( | ||||||
|  |             child: PagingHelperView( | ||||||
|  |               provider: socialCreditHistoryNotifierProvider, | ||||||
|  |               futureRefreshable: socialCreditHistoryNotifierProvider.future, | ||||||
|  |               notifierRefreshable: socialCreditHistoryNotifierProvider.notifier, | ||||||
|  |               contentBuilder: | ||||||
|  |                   (data, widgetCount, endItemView) => ListView.builder( | ||||||
|  |                     padding: EdgeInsets.zero, | ||||||
|  |                     itemCount: widgetCount, | ||||||
|  |                     itemBuilder: (context, index) { | ||||||
|  |                       if (index == widgetCount - 1) { | ||||||
|  |                         return endItemView; | ||||||
|  |                       } | ||||||
|  |                       final record = data.items[index]; | ||||||
|  |                       return ListTile( | ||||||
|  |                         contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                         title: Text(record.reason), | ||||||
|  |                         subtitle: Text( | ||||||
|  |                           DateFormat.yMMMd().format(record.createdAt), | ||||||
|  |                         ), | ||||||
|  |                         trailing: Text( | ||||||
|  |                           record.delta > 0 | ||||||
|  |                               ? '+${record.delta}' | ||||||
|  |                               : '${record.delta}', | ||||||
|  |                           style: TextStyle( | ||||||
|  |                             color: record.delta > 0 ? Colors.green : Colors.red, | ||||||
|  |                           ), | ||||||
|  |                         ), | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								lib/screens/account/credits.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								lib/screens/account/credits.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'credits.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // RiverpodGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | String _$socialCreditsHash() => r'2599844e892127ee4d315caced5c10e4dbaea142'; | ||||||
|  |  | ||||||
|  | /// See also [socialCredits]. | ||||||
|  | @ProviderFor(socialCredits) | ||||||
|  | final socialCreditsProvider = AutoDisposeFutureProvider<double>.internal( | ||||||
|  |   socialCredits, | ||||||
|  |   name: r'socialCreditsProvider', | ||||||
|  |   debugGetCreateSourceHash: | ||||||
|  |       const bool.fromEnvironment('dart.vm.product') | ||||||
|  |           ? null | ||||||
|  |           : _$socialCreditsHash, | ||||||
|  |   dependencies: null, | ||||||
|  |   allTransitiveDependencies: null, | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | typedef SocialCreditsRef = AutoDisposeFutureProviderRef<double>; | ||||||
|  | String _$socialCreditHistoryNotifierHash() => | ||||||
|  |     r'950db020754160f835c64cedf3fa2175e61e4d64'; | ||||||
|  |  | ||||||
|  | /// See also [SocialCreditHistoryNotifier]. | ||||||
|  | @ProviderFor(SocialCreditHistoryNotifier) | ||||||
|  | final socialCreditHistoryNotifierProvider = AutoDisposeAsyncNotifierProvider< | ||||||
|  |   SocialCreditHistoryNotifier, | ||||||
|  |   CursorPagingData<SnSocialCreditRecord> | ||||||
|  | >.internal( | ||||||
|  |   SocialCreditHistoryNotifier.new, | ||||||
|  |   name: r'socialCreditHistoryNotifierProvider', | ||||||
|  |   debugGetCreateSourceHash: | ||||||
|  |       const bool.fromEnvironment('dart.vm.product') | ||||||
|  |           ? null | ||||||
|  |           : _$socialCreditHistoryNotifierHash, | ||||||
|  |   dependencies: null, | ||||||
|  |   allTransitiveDependencies: null, | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | typedef _$SocialCreditHistoryNotifier = | ||||||
|  |     AutoDisposeAsyncNotifier<CursorPagingData<SnSocialCreditRecord>>; | ||||||
|  | // ignore_for_file: type=lint | ||||||
|  | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
| @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:gap/gap.dart'; | import 'package:gap/gap.dart'; | ||||||
| import 'package:google_fonts/google_fonts.dart'; | import 'package:google_fonts/google_fonts.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/account.dart'; | ||||||
| import 'package:island/models/wallet.dart'; | import 'package:island/models/wallet.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/pods/userinfo.dart'; | import 'package:island/pods/userinfo.dart'; | ||||||
| @@ -19,6 +20,7 @@ import 'package:island/widgets/payment/payment_overlay.dart'; | |||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  | import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
| part 'leveling.g.dart'; | part 'leveling.g.dart'; | ||||||
| @@ -35,13 +37,49 @@ Future<SnWalletSubscription?> accountStellarSubscription(Ref ref) async { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | class LevelingHistoryNotifier extends _$LevelingHistoryNotifier | ||||||
|  |     with CursorPagingNotifierMixin<SnExperienceRecord> { | ||||||
|  |   static const int _pageSize = 20; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<CursorPagingData<SnExperienceRecord>> build() => fetch(cursor: null); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<CursorPagingData<SnExperienceRecord>> fetch({ | ||||||
|  |     required String? cursor, | ||||||
|  |   }) async { | ||||||
|  |     final client = ref.read(apiClientProvider); | ||||||
|  |     final offset = cursor == null ? 0 : int.parse(cursor); | ||||||
|  |  | ||||||
|  |     final queryParams = {'offset': offset, 'take': _pageSize}; | ||||||
|  |  | ||||||
|  |     final response = await client.get( | ||||||
|  |       '/id/accounts/me/leveling', | ||||||
|  |       queryParameters: queryParams, | ||||||
|  |     ); | ||||||
|  |     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||||
|  |     final List<dynamic> data = response.data; | ||||||
|  |     final records = | ||||||
|  |         data.map((json) => SnExperienceRecord.fromJson(json)).toList(); | ||||||
|  |  | ||||||
|  |     final hasMore = offset + records.length < total; | ||||||
|  |     final nextCursor = hasMore ? (offset + records.length).toString() : null; | ||||||
|  |  | ||||||
|  |     return CursorPagingData( | ||||||
|  |       items: records, | ||||||
|  |       hasMore: hasMore, | ||||||
|  |       nextCursor: nextCursor, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| class LevelingScreen extends HookConsumerWidget { | class LevelingScreen extends HookConsumerWidget { | ||||||
|   const LevelingScreen({super.key}); |   const LevelingScreen({super.key}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final user = ref.watch(userInfoProvider); |     final user = ref.watch(userInfoProvider); | ||||||
|     final stellarSubscription = ref.watch(accountStellarSubscriptionProvider); |  | ||||||
|  |  | ||||||
|     if (user.value == null) { |     if (user.value == null) { | ||||||
|       return AppScaffold( |       return AppScaffold( | ||||||
| @@ -50,13 +88,156 @@ class LevelingScreen extends HookConsumerWidget { | |||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     final currentLevel = user.value!.profile.level; |     return DefaultTabController( | ||||||
|     final currentExp = user.value!.profile.experience; |       length: 2, | ||||||
|     final progress = user.value!.profile.levelingProgress; |       child: AppScaffold( | ||||||
|  |         appBar: AppBar( | ||||||
|  |           title: Text('levelingProgress'.tr()), | ||||||
|  |           bottom: TabBar( | ||||||
|  |             tabs: [ | ||||||
|  |               Tab( | ||||||
|  |                 child: Text( | ||||||
|  |                   'leveling'.tr(), | ||||||
|  |                   textAlign: TextAlign.center, | ||||||
|  |                   style: TextStyle( | ||||||
|  |                     color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               Tab( | ||||||
|  |                 child: Text( | ||||||
|  |                   'stellarProgram'.tr(), | ||||||
|  |                   textAlign: TextAlign.center, | ||||||
|  |                   style: TextStyle( | ||||||
|  |                     color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         body: TabBarView( | ||||||
|  |           children: [ | ||||||
|  |             _buildLevelingTab(context, ref, user.value!), | ||||||
|  |             _buildStellarProgramTab(context, ref), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|     return AppScaffold( |   Widget _buildLevelingTab( | ||||||
|       appBar: AppBar(title: Text('levelingProgress'.tr())), |     BuildContext context, | ||||||
|       body: SingleChildScrollView( |     WidgetRef ref, | ||||||
|  |     SnAccount user, | ||||||
|  |   ) { | ||||||
|  |     final currentLevel = user.profile.level; | ||||||
|  |     final currentExp = user.profile.experience; | ||||||
|  |     final progress = user.profile.levelingProgress; | ||||||
|  |  | ||||||
|  |     return Center( | ||||||
|  |       child: Container( | ||||||
|  |         padding: const EdgeInsets.symmetric(horizontal: 20), | ||||||
|  |         constraints: const BoxConstraints(maxWidth: 480), | ||||||
|  |         child: CustomScrollView( | ||||||
|  |           slivers: [ | ||||||
|  |             const SliverGap(20), | ||||||
|  |  | ||||||
|  |             // Current Progress Card | ||||||
|  |             SliverToBoxAdapter( | ||||||
|  |               child: LevelingProgressCard( | ||||||
|  |                 level: currentLevel, | ||||||
|  |                 experience: currentExp, | ||||||
|  |                 progress: progress, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             const SliverGap(24), | ||||||
|  |  | ||||||
|  |             // Level Stairs Graph | ||||||
|  |             SliverToBoxAdapter( | ||||||
|  |               child: Text( | ||||||
|  |                 'levelProgress'.tr(), | ||||||
|  |                 style: Theme.of(context).textTheme.headlineSmall?.copyWith( | ||||||
|  |                   fontWeight: FontWeight.bold, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             const SliverGap(16), | ||||||
|  |  | ||||||
|  |             // Stairs visualization with fixed height and horizontal scroll | ||||||
|  |             SliverToBoxAdapter(child: _buildLevelStairs(context, currentLevel)), | ||||||
|  |             const SliverGap(24), | ||||||
|  |  | ||||||
|  |             // Leveling History | ||||||
|  |             SliverToBoxAdapter( | ||||||
|  |               child: Text( | ||||||
|  |                 'levelingHistory'.tr(), | ||||||
|  |                 style: Theme.of(context).textTheme.headlineSmall?.copyWith( | ||||||
|  |                   fontWeight: FontWeight.bold, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             const SliverGap(8), | ||||||
|  |             PagingHelperSliverView( | ||||||
|  |               provider: levelingHistoryNotifierProvider, | ||||||
|  |               futureRefreshable: levelingHistoryNotifierProvider.future, | ||||||
|  |               notifierRefreshable: levelingHistoryNotifierProvider.notifier, | ||||||
|  |               contentBuilder: | ||||||
|  |                   (data, widgetCount, endItemView) => SliverList.builder( | ||||||
|  |                     itemCount: widgetCount, | ||||||
|  |                     itemBuilder: (context, index) { | ||||||
|  |                       if (index == widgetCount - 1) { | ||||||
|  |                         return endItemView; | ||||||
|  |                       } | ||||||
|  |                       final record = data.items[index]; | ||||||
|  |                       return ListTile( | ||||||
|  |                         title: Column( | ||||||
|  |                           mainAxisSize: MainAxisSize.min, | ||||||
|  |                           crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                           children: [ | ||||||
|  |                             Text(record.reason), | ||||||
|  |                             Row( | ||||||
|  |                               spacing: 4, | ||||||
|  |                               children: [ | ||||||
|  |                                 Text( | ||||||
|  |                                   record.createdAt.formatRelative(context), | ||||||
|  |                                 ).fontSize(13), | ||||||
|  |                                 Text('·').fontSize(13).bold(), | ||||||
|  |                                 Text( | ||||||
|  |                                   record.createdAt.formatSystem(), | ||||||
|  |                                 ).fontSize(13), | ||||||
|  |                               ], | ||||||
|  |                             ).opacity(0.8), | ||||||
|  |                           ], | ||||||
|  |                         ), | ||||||
|  |                         subtitle: Row( | ||||||
|  |                           spacing: 8, | ||||||
|  |                           children: [ | ||||||
|  |                             Text( | ||||||
|  |                               '${record.delta > 0 ? '+' : ''}${record.delta} EXP', | ||||||
|  |                             ), | ||||||
|  |                             if (record.bonusMultiplier != 1.0) | ||||||
|  |                               Text('x${record.bonusMultiplier}'), | ||||||
|  |                           ], | ||||||
|  |                         ), | ||||||
|  |                         minTileHeight: 56, | ||||||
|  |                         contentPadding: EdgeInsets.symmetric(horizontal: 4), | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |             ), | ||||||
|  |  | ||||||
|  |             SliverGap(getTabbedPadding(context, vertical: 20).vertical), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget _buildStellarProgramTab(BuildContext context, WidgetRef ref) { | ||||||
|  |     final stellarSubscription = ref.watch(accountStellarSubscriptionProvider); | ||||||
|  |  | ||||||
|  |     return SingleChildScrollView( | ||||||
|       padding: getTabbedPadding(context, horizontal: 20, vertical: 20), |       padding: getTabbedPadding(context, horizontal: 20, vertical: 20), | ||||||
|       child: Center( |       child: Center( | ||||||
|         child: ConstrainedBox( |         child: ConstrainedBox( | ||||||
| @@ -64,36 +245,12 @@ class LevelingScreen extends HookConsumerWidget { | |||||||
|           child: Column( |           child: Column( | ||||||
|             crossAxisAlignment: CrossAxisAlignment.stretch, |             crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|             children: [ |             children: [ | ||||||
|                 // Current Progress Card |  | ||||||
|                 LevelingProgressCard( |  | ||||||
|                   level: currentLevel, |  | ||||||
|                   experience: currentExp, |  | ||||||
|                   progress: progress, |  | ||||||
|                 ), |  | ||||||
|                 const Gap(24), |  | ||||||
|  |  | ||||||
|                 // Level Stairs Graph |  | ||||||
|                 Text( |  | ||||||
|                   'levelProgress'.tr(), |  | ||||||
|                   style: Theme.of(context).textTheme.headlineSmall?.copyWith( |  | ||||||
|                     fontWeight: FontWeight.bold, |  | ||||||
|                   ), |  | ||||||
|                 ), |  | ||||||
|                 const Gap(16), |  | ||||||
|  |  | ||||||
|                 // Stairs visualization with fixed height and horizontal scroll |  | ||||||
|                 _buildLevelStairs(context, currentLevel), |  | ||||||
|  |  | ||||||
|                 const Gap(24), |  | ||||||
|  |  | ||||||
|                 // Membership section |  | ||||||
|               _buildMembershipSection(context, ref, stellarSubscription), |               _buildMembershipSection(context, ref, stellarSubscription), | ||||||
|               const Gap(16), |               const Gap(16), | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|       ), |  | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,5 +27,26 @@ final accountStellarSubscriptionProvider = | |||||||
| // ignore: unused_element | // ignore: unused_element | ||||||
| typedef AccountStellarSubscriptionRef = | typedef AccountStellarSubscriptionRef = | ||||||
|     AutoDisposeFutureProviderRef<SnWalletSubscription?>; |     AutoDisposeFutureProviderRef<SnWalletSubscription?>; | ||||||
|  | String _$levelingHistoryNotifierHash() => | ||||||
|  |     r'e795f9b7911c9e50f15c095ea237cb0e87bf1e89'; | ||||||
|  |  | ||||||
|  | /// See also [LevelingHistoryNotifier]. | ||||||
|  | @ProviderFor(LevelingHistoryNotifier) | ||||||
|  | final levelingHistoryNotifierProvider = AutoDisposeAsyncNotifierProvider< | ||||||
|  |   LevelingHistoryNotifier, | ||||||
|  |   CursorPagingData<SnExperienceRecord> | ||||||
|  | >.internal( | ||||||
|  |   LevelingHistoryNotifier.new, | ||||||
|  |   name: r'levelingHistoryNotifierProvider', | ||||||
|  |   debugGetCreateSourceHash: | ||||||
|  |       const bool.fromEnvironment('dart.vm.product') | ||||||
|  |           ? null | ||||||
|  |           : _$levelingHistoryNotifierHash, | ||||||
|  |   dependencies: null, | ||||||
|  |   allTransitiveDependencies: null, | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | typedef _$LevelingHistoryNotifier = | ||||||
|  |     AutoDisposeAsyncNotifier<CursorPagingData<SnExperienceRecord>>; | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/models/auth.dart'; | import 'package:island/models/auth.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/pods/userinfo.dart'; | import 'package:island/pods/userinfo.dart'; | ||||||
| import 'package:island/screens/account/me/settings_auth_factors.dart'; | import 'package:island/screens/account/me/settings_auth_factors.dart'; | ||||||
| @@ -14,8 +14,7 @@ import 'package:island/screens/account/me/settings_connections.dart'; | |||||||
| import 'package:island/screens/account/me/settings_contacts.dart'; | import 'package:island/screens/account/me/settings_contacts.dart'; | ||||||
| import 'package:island/screens/auth/captcha.dart'; | import 'package:island/screens/auth/captcha.dart'; | ||||||
| import 'package:island/screens/auth/login.dart'; | import 'package:island/screens/auth/login.dart'; | ||||||
| import 'package:island/services/responsive.dart'; | import 'package:island/widgets/account/account_devices.dart'; | ||||||
| import 'package:island/widgets/account/account_session_sheet.dart'; |  | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/response.dart'; | import 'package:island/widgets/response.dart'; | ||||||
| @@ -23,7 +22,7 @@ import 'package:material_symbols_icons/symbols.dart'; | |||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
| 
 | 
 | ||||||
| part 'settings.g.dart'; | part 'account_settings.g.dart'; | ||||||
| 
 | 
 | ||||||
| @riverpod | @riverpod | ||||||
| Future<List<SnAuthFactor>> authFactors(Ref ref) async { | Future<List<SnAuthFactor>> authFactors(Ref ref) async { | ||||||
| @@ -57,7 +56,6 @@ class AccountSettingsScreen extends HookConsumerWidget { | |||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final isDesktop = |     final isDesktop = | ||||||
|         !kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux); |         !kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux); | ||||||
|     final isWide = isWideScreen(context); |  | ||||||
| 
 | 
 | ||||||
|     Future<void> requestAccountDeletion() async { |     Future<void> requestAccountDeletion() async { | ||||||
|       final confirm = await showConfirmAlert( |       final confirm = await showConfirmAlert( | ||||||
| @@ -440,37 +438,6 @@ class AccountSettingsScreen extends HookConsumerWidget { | |||||||
| 
 | 
 | ||||||
|     // Create a responsive layout based on screen width |     // Create a responsive layout based on screen width | ||||||
|     Widget buildSettingsList() { |     Widget buildSettingsList() { | ||||||
|       if (isWide) { |  | ||||||
|         // Two-column layout for wide screens |  | ||||||
|         return Row( |  | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|           children: [ |  | ||||||
|             Expanded( |  | ||||||
|               child: Column( |  | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|                 children: [ |  | ||||||
|                   _SettingsSection( |  | ||||||
|                     title: 'accountSecurityTitle', |  | ||||||
|                     children: securitySettings, |  | ||||||
|                   ), |  | ||||||
|                 ], |  | ||||||
|               ), |  | ||||||
|             ), |  | ||||||
|             Expanded( |  | ||||||
|               child: Column( |  | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|                 children: [ |  | ||||||
|                   _SettingsSection( |  | ||||||
|                     title: 'accountDangerZoneTitle', |  | ||||||
|                     children: dangerZoneSettings, |  | ||||||
|                   ), |  | ||||||
|                 ], |  | ||||||
|               ), |  | ||||||
|             ), |  | ||||||
|           ], |  | ||||||
|         ); |  | ||||||
|       } else { |  | ||||||
|         // Single column layout for narrow screens |  | ||||||
|       return Column( |       return Column( | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|         children: [ |         children: [ | ||||||
| @@ -485,7 +452,6 @@ class AccountSettingsScreen extends HookConsumerWidget { | |||||||
|         ], |         ], | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     return AppScaffold( |     return AppScaffold( | ||||||
|       appBar: AppBar( |       appBar: AppBar( | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
| 
 | 
 | ||||||
| part of 'settings.dart'; | part of 'account_settings.dart'; | ||||||
| 
 | 
 | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import 'package:collection/collection.dart'; | ||||||
| import 'package:croppy/croppy.dart' hide cropImage; | import 'package:croppy/croppy.dart' hide cropImage; | ||||||
| import 'package:dropdown_button2/dropdown_button2.dart'; | import 'package:dropdown_button2/dropdown_button2.dart'; | ||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
| @@ -7,7 +8,7 @@ import 'package:gap/gap.dart'; | |||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:image_picker/image_picker.dart'; | import 'package:image_picker/image_picker.dart'; | ||||||
| import 'package:island/models/file.dart'; | import 'package:island/models/file.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
| import 'package:island/pods/config.dart'; | import 'package:island/pods/config.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/pods/userinfo.dart'; | import 'package:island/pods/userinfo.dart'; | ||||||
| @@ -20,6 +21,7 @@ import 'package:material_symbols_icons/symbols.dart'; | |||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
| 
 | 
 | ||||||
| const kServerSupportedLanguages = {'en-US': 'en-us', 'zh-CN': 'zh-hans'}; | const kServerSupportedLanguages = {'en-US': 'en-us', 'zh-CN': 'zh-hans'}; | ||||||
|  | const kServerSupportedRegions = ['US', 'JP', 'CN']; | ||||||
| 
 | 
 | ||||||
| class UpdateProfileScreen extends HookConsumerWidget { | class UpdateProfileScreen extends HookConsumerWidget { | ||||||
|   const UpdateProfileScreen({super.key}); |   const UpdateProfileScreen({super.key}); | ||||||
| @@ -96,6 +98,7 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|     final usernameController = useTextEditingController(text: user.value!.name); |     final usernameController = useTextEditingController(text: user.value!.name); | ||||||
|     final nicknameController = useTextEditingController(text: user.value!.nick); |     final nicknameController = useTextEditingController(text: user.value!.nick); | ||||||
|     final language = useState(user.value!.language); |     final language = useState(user.value!.language); | ||||||
|  |     final region = useState(user.value!.region); | ||||||
|     final links = useState<List<ProfileLink>>(user.value!.profile.links); |     final links = useState<List<ProfileLink>>(user.value!.profile.links); | ||||||
| 
 | 
 | ||||||
|     void updateBasicInfo() async { |     void updateBasicInfo() async { | ||||||
| @@ -110,6 +113,7 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|             'name': usernameController.text, |             'name': usernameController.text, | ||||||
|             'nick': nicknameController.text, |             'nick': nicknameController.text, | ||||||
|             'language': language.value, |             'language': language.value, | ||||||
|  |             'region': region.value, | ||||||
|           }, |           }, | ||||||
|         ); |         ); | ||||||
|         final userNotifier = ref.read(userInfoProvider.notifier); |         final userNotifier = ref.read(userInfoProvider.notifier); | ||||||
| @@ -168,11 +172,18 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|             'location': locationController.text, |             'location': locationController.text, | ||||||
|             'time_zone': timeZoneController.text, |             'time_zone': timeZoneController.text, | ||||||
|             'birthday': birthday.value?.toUtc().toIso8601String(), |             'birthday': birthday.value?.toUtc().toIso8601String(), | ||||||
|             'links': links.value, |             'links': | ||||||
|  |                 links.value | ||||||
|  |                     .where((e) => e.name.isNotEmpty && e.url.isNotEmpty) | ||||||
|  |                     .toList(), | ||||||
|           }, |           }, | ||||||
|         ); |         ); | ||||||
|         final userNotifier = ref.read(userInfoProvider.notifier); |         final userNotifier = ref.read(userInfoProvider.notifier); | ||||||
|         userNotifier.fetchUser(); |         userNotifier.fetchUser(); | ||||||
|  |         links.value = | ||||||
|  |             links.value | ||||||
|  |                 .where((e) => e.name.isNotEmpty && e.url.isNotEmpty) | ||||||
|  |                 .toList(); | ||||||
|       } catch (err) { |       } catch (err) { | ||||||
|         showErrorAlert(err); |         showErrorAlert(err); | ||||||
|       } finally { |       } finally { | ||||||
| @@ -283,6 +294,32 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|                       ], |                       ], | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
|  |                   DropdownButtonFormField2<String>( | ||||||
|  |                     decoration: InputDecoration( | ||||||
|  |                       labelText: 'region'.tr(), | ||||||
|  |                       helperText: 'accountRegionHint'.tr(), | ||||||
|  |                     ), | ||||||
|  |                     items: [ | ||||||
|  |                       ...kServerSupportedRegions.map( | ||||||
|  |                         (e) => DropdownMenuItem(value: e, child: Text(e)), | ||||||
|  |                       ), | ||||||
|  |                       if (!kServerSupportedRegions.contains(region.value)) | ||||||
|  |                         DropdownMenuItem( | ||||||
|  |                           value: region.value, | ||||||
|  |                           child: Text(region.value), | ||||||
|  |                         ), | ||||||
|  |                     ], | ||||||
|  |                     value: region.value, | ||||||
|  |                     onChanged: (value) { | ||||||
|  |                       region.value = value ?? region.value; | ||||||
|  |                     }, | ||||||
|  |                     customButton: Row( | ||||||
|  |                       children: [ | ||||||
|  |                         Expanded(child: Text(region.value)), | ||||||
|  |                         Icon(Symbols.arrow_drop_down), | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|                   Align( |                   Align( | ||||||
|                     alignment: Alignment.centerRight, |                     alignment: Alignment.centerRight, | ||||||
|                     child: TextButton.icon( |                     child: TextButton.icon( | ||||||
| @@ -568,6 +605,7 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|                     children: [ |                     children: [ | ||||||
|                       for (var i = 0; i < links.value.length; i++) |                       for (var i = 0; i < links.value.length; i++) | ||||||
|                         Row( |                         Row( | ||||||
|  |                           key: ValueKey(links.value[i].hashCode), | ||||||
|                           crossAxisAlignment: CrossAxisAlignment.end, |                           crossAxisAlignment: CrossAxisAlignment.end, | ||||||
|                           children: [ |                           children: [ | ||||||
|                             Expanded( |                             Expanded( | ||||||
| @@ -610,8 +648,10 @@ class UpdateProfileScreen extends HookConsumerWidget { | |||||||
|                             IconButton( |                             IconButton( | ||||||
|                               icon: const Icon(Symbols.delete), |                               icon: const Icon(Symbols.delete), | ||||||
|                               onPressed: () { |                               onPressed: () { | ||||||
|                                 links.value = List.from(links.value) |                                 links.value = | ||||||
|                                   ..removeAt(i); |                                     links.value | ||||||
|  |                                         .whereIndexed((idx, _) => idx != i) | ||||||
|  |                                         .toList(); | ||||||
|                               }, |                               }, | ||||||
|                             ), |                             ), | ||||||
|                           ], |                           ], | ||||||
| @@ -1,14 +1,16 @@ | |||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
| import 'package:flutter_svg/flutter_svg.dart'; | import 'package:flutter_svg/flutter_svg.dart'; | ||||||
| import 'package:gap/gap.dart'; | import 'package:gap/gap.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/models/auth.dart'; | import 'package:island/models/auth.dart'; | ||||||
|  | import 'package:island/pods/config.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/screens/account/me/settings.dart'; | import 'package:island/screens/account/me/account_settings.dart'; | ||||||
| import 'package:island/screens/auth/oidc.native.dart'; | import 'package:island/screens/auth/oidc.native.dart'; | ||||||
| import 'package:island/services/text.dart'; | import 'package:island/utils/text.dart'; | ||||||
| import 'package:island/services/time.dart'; | import 'package:island/services/time.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/content/sheet.dart'; | import 'package:island/widgets/content/sheet.dart'; | ||||||
| @@ -16,6 +18,7 @@ import 'package:island/widgets/response.dart'; | |||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:sign_in_with_apple/sign_in_with_apple.dart'; | import 'package:sign_in_with_apple/sign_in_with_apple.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  | import 'package:url_launcher/url_launcher_string.dart'; | ||||||
|  |  | ||||||
| // Helper function to get provider icon and localized name | // Helper function to get provider icon and localized name | ||||||
| Widget getProviderIcon(String provider, {double size = 24, Color? color}) { | Widget getProviderIcon(String provider, {double size = 24, Color? color}) { | ||||||
| @@ -165,9 +168,7 @@ class AccountConnectionNewSheet extends HookConsumerWidget { | |||||||
|               scopes: [AppleIDAuthorizationScopes.email], |               scopes: [AppleIDAuthorizationScopes.email], | ||||||
|               webAuthenticationOptions: WebAuthenticationOptions( |               webAuthenticationOptions: WebAuthenticationOptions( | ||||||
|                 clientId: 'dev.solsynth.solarpass', |                 clientId: 'dev.solsynth.solarpass', | ||||||
|                 redirectUri: Uri.parse( |                 redirectUri: Uri.parse('https://id.solian.app/auth/callback'), | ||||||
|                   'https://id.solian.app/auth/callback/apple', |  | ||||||
|                 ), |  | ||||||
|               ), |               ), | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
| @@ -195,6 +196,13 @@ class AccountConnectionNewSheet extends HookConsumerWidget { | |||||||
|         case 'github': |         case 'github': | ||||||
|         case 'discord': |         case 'discord': | ||||||
|         case 'afdian': |         case 'afdian': | ||||||
|  |           if (kIsWeb) { | ||||||
|  |             final serverUrl = ref.watch(serverUrlProvider); | ||||||
|  |             final accessToken = ref.watch(tokenProvider); | ||||||
|  |             launchUrlString( | ||||||
|  |               '$serverUrl/id/auth/login/${selectedProvider.value}?tk=${accessToken!.token}', | ||||||
|  |             ); | ||||||
|  |           } else { | ||||||
|             await Navigator.of(context, rootNavigator: true).push( |             await Navigator.of(context, rootNavigator: true).push( | ||||||
|               MaterialPageRoute( |               MaterialPageRoute( | ||||||
|                 builder: |                 builder: | ||||||
| @@ -206,6 +214,7 @@ class AccountConnectionNewSheet extends HookConsumerWidget { | |||||||
|               ), |               ), | ||||||
|             ); |             ); | ||||||
|             if (context.mounted) Navigator.pop(context, true); |             if (context.mounted) Navigator.pop(context, true); | ||||||
|  |           } | ||||||
|           break; |           break; | ||||||
|         default: |         default: | ||||||
|           showSnackBar('accountConnectionAddError'.tr()); |           showSnackBar('accountConnectionAddError'.tr()); | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
| import 'package:gap/gap.dart'; | import 'package:gap/gap.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/content/sheet.dart'; | import 'package:island/widgets/content/sheet.dart'; | ||||||
|   | |||||||
| @@ -2,20 +2,23 @@ import 'package:dio/dio.dart'; | |||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
| import 'package:flutter/foundation.dart'; | import 'package:flutter/foundation.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter/services.dart'; | ||||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
| import 'package:go_router/go_router.dart'; | import 'package:go_router/go_router.dart'; | ||||||
| import 'package:gap/gap.dart'; | import 'package:gap/gap.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/models/chat.dart'; | import 'package:island/models/chat.dart'; | ||||||
|  | import 'package:island/models/developer.dart'; | ||||||
|  | import 'package:island/models/publisher.dart'; | ||||||
| import 'package:island/models/relationship.dart'; | import 'package:island/models/relationship.dart'; | ||||||
| import 'package:island/models/user.dart'; | import 'package:island/models/account.dart'; | ||||||
| import 'package:island/pods/config.dart'; | import 'package:island/pods/config.dart'; | ||||||
| import 'package:island/pods/event_calendar.dart'; | import 'package:island/pods/event_calendar.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/pods/userinfo.dart'; | import 'package:island/pods/userinfo.dart'; | ||||||
| import 'package:island/services/color.dart'; | import 'package:island/services/color.dart'; | ||||||
| import 'package:island/services/responsive.dart'; | import 'package:island/services/responsive.dart'; | ||||||
| import 'package:island/services/text.dart'; | import 'package:island/utils/text.dart'; | ||||||
| import 'package:island/services/time.dart'; | import 'package:island/services/time.dart'; | ||||||
| import 'package:island/services/timezone/native.dart'; | import 'package:island/services/timezone/native.dart'; | ||||||
| import 'package:island/widgets/account/account_name.dart'; | import 'package:island/widgets/account/account_name.dart'; | ||||||
| @@ -37,166 +40,107 @@ import 'package:url_launcher/url_launcher_string.dart'; | |||||||
|  |  | ||||||
| part 'profile.g.dart'; | part 'profile.g.dart'; | ||||||
|  |  | ||||||
| @riverpod | class _AccountBasicInfo extends StatelessWidget { | ||||||
| Future<SnAccount> account(Ref ref, String uname) async { |   final SnAccount data; | ||||||
|   if (uname == 'me') { |   final String uname; | ||||||
|     final userInfo = ref.watch(userInfoProvider); |   final AsyncValue<SnDeveloper?> accountDeveloper; | ||||||
|     if (userInfo.hasValue && userInfo.value != null) { |  | ||||||
|       return userInfo.value!; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   final apiClient = ref.watch(apiClientProvider); |  | ||||||
|   final resp = await apiClient.get("/id/accounts/$uname"); |  | ||||||
|   return SnAccount.fromJson(resp.data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @riverpod |   const _AccountBasicInfo({ | ||||||
| Future<List<SnAccountBadge>> accountBadges(Ref ref, String uname) async { |     required this.data, | ||||||
|   final apiClient = ref.watch(apiClientProvider); |     required this.uname, | ||||||
|   final resp = await apiClient.get("/id/accounts/$uname/badges"); |     required this.accountDeveloper, | ||||||
|   return List<SnAccountBadge>.from( |   }); | ||||||
|     resp.data.map((x) => SnAccountBadge.fromJson(x)), |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @riverpod |  | ||||||
| Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async { |  | ||||||
|   try { |  | ||||||
|     final account = await ref.watch(accountProvider(uname).future); |  | ||||||
|     if (account.profile.background == null) return null; |  | ||||||
|     final palette = await PaletteGenerator.fromImageProvider( |  | ||||||
|       CloudImageWidget.provider( |  | ||||||
|         fileId: account.profile.background!.id, |  | ||||||
|         serverUrl: ref.watch(serverUrlProvider), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|     final dominantColor = palette.dominantColor?.color; |  | ||||||
|     if (dominantColor == null) return null; |  | ||||||
|     return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; |  | ||||||
|   } catch (_) { |  | ||||||
|     return null; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @riverpod |  | ||||||
| Future<SnChatRoom?> accountDirectChat(Ref ref, String uname) async { |  | ||||||
|   final userInfo = ref.watch(userInfoProvider); |  | ||||||
|   if (userInfo.value == null) return null; |  | ||||||
|   final account = await ref.watch(accountProvider(uname).future); |  | ||||||
|   final apiClient = ref.watch(apiClientProvider); |  | ||||||
|   try { |  | ||||||
|     final resp = await apiClient.get("/sphere/chat/direct/${account.id}"); |  | ||||||
|     return SnChatRoom.fromJson(resp.data); |  | ||||||
|   } catch (err) { |  | ||||||
|     if (err is DioException && err.response?.statusCode == 404) { |  | ||||||
|       return null; |  | ||||||
|     } |  | ||||||
|     rethrow; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @riverpod |  | ||||||
| Future<SnRelationship?> accountRelationship(Ref ref, String uname) async { |  | ||||||
|   final userInfo = ref.watch(userInfoProvider); |  | ||||||
|   if (userInfo.value == null) return null; |  | ||||||
|   final account = await ref.watch(accountProvider(uname).future); |  | ||||||
|   final apiClient = ref.watch(apiClientProvider); |  | ||||||
|   try { |  | ||||||
|     final resp = await apiClient.get("/id/relationships/${account.id}"); |  | ||||||
|     return SnRelationship.fromJson(resp.data); |  | ||||||
|   } catch (err) { |  | ||||||
|     if (err is DioException && err.response?.statusCode == 404) { |  | ||||||
|       return null; |  | ||||||
|     } |  | ||||||
|     rethrow; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| class AccountProfileScreen extends HookConsumerWidget { |  | ||||||
|   final String name; |  | ||||||
|   const AccountProfileScreen({super.key, required this.name}); |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context) { | ||||||
|     final now = DateTime.now(); |     return Padding( | ||||||
|  |       padding: const EdgeInsets.fromLTRB(24, 24, 24, 8), | ||||||
|     final account = ref.watch(accountProvider(name)); |       child: Row( | ||||||
|     final accountEvents = ref.watch( |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|       eventCalendarProvider( |         children: [ | ||||||
|         EventCalendarQuery(uname: name, year: now.year, month: now.month), |           ProfilePictureWidget(file: data.profile.picture, radius: 32), | ||||||
|  |           const Gap(20), | ||||||
|  |           Expanded( | ||||||
|  |             child: Column( | ||||||
|  |               crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |               children: [ | ||||||
|  |                 Row( | ||||||
|  |                   children: [ | ||||||
|  |                     AccountName(account: data, style: TextStyle(fontSize: 20)), | ||||||
|  |                     const Gap(6), | ||||||
|  |                     Flexible( | ||||||
|  |                       child: Text( | ||||||
|  |                         '@${data.name}', | ||||||
|  |                         maxLines: 1, | ||||||
|  |                         overflow: TextOverflow.ellipsis, | ||||||
|  |                       ).fontSize(14).opacity(0.85), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 if (accountDeveloper.value != null) | ||||||
|  |                   Row( | ||||||
|  |                     spacing: 7, | ||||||
|  |                     children: [ | ||||||
|  |                       const Icon(Symbols.smart_toy, size: 18), | ||||||
|  |                       Text( | ||||||
|  |                         'botAutomatedBy'.tr( | ||||||
|  |                           args: [accountDeveloper.value!.publisher!.nick], | ||||||
|  |                         ), | ||||||
|  |                       ).fontSize(13), | ||||||
|  |                     ], | ||||||
|  |                   ).opacity(0.75), | ||||||
|  |                 const Gap(4), | ||||||
|  |                 AccountStatusWidget(uname: uname, padding: EdgeInsets.zero), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           IconButton( | ||||||
|  |             onPressed: () { | ||||||
|  |               SharePlus.instance.share( | ||||||
|  |                 ShareParams( | ||||||
|  |                   uri: Uri.parse('https://id.solian.app/@${data.name}'), | ||||||
|                 ), |                 ), | ||||||
|               ); |               ); | ||||||
|     final accountChat = ref.watch(accountDirectChatProvider(name)); |             }, | ||||||
|     final accountRelationship = ref.watch(accountRelationshipProvider(name)); |             icon: const Icon(Symbols.share), | ||||||
|  |           ), | ||||||
|     final appbarColor = ref.watch(accountAppbarForcegroundColorProvider(name)); |         ], | ||||||
|  |       ), | ||||||
|     final appbarShadow = Shadow( |  | ||||||
|       color: appbarColor.value?.invert ?? Colors.transparent, |  | ||||||
|       blurRadius: 5.0, |  | ||||||
|       offset: Offset(1.0, 1.0), |  | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     Future<void> relationshipAction() async { |  | ||||||
|       if (accountRelationship.value != null) return; |  | ||||||
|       showLoadingModal(context); |  | ||||||
|       try { |  | ||||||
|         final client = ref.watch(apiClientProvider); |  | ||||||
|         await client.post('/id/relationships/${account.value!.id}/friends'); |  | ||||||
|         ref.invalidate(accountRelationshipProvider(name)); |  | ||||||
|       } catch (err) { |  | ||||||
|         showErrorAlert(err); |  | ||||||
|       } finally { |  | ||||||
|         if (context.mounted) hideLoadingModal(context); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|     Future<void> blockAction() async { | class _AccountProfileBio extends StatelessWidget { | ||||||
|       showLoadingModal(context); |   final SnAccount data; | ||||||
|       try { |  | ||||||
|         final client = ref.watch(apiClientProvider); |  | ||||||
|         if (accountRelationship.value == null) { |  | ||||||
|           await client.post('/id/relationships/${account.value!.id}/block'); |  | ||||||
|         } else { |  | ||||||
|           await client.delete('/id/relationships/${account.value!.id}/block'); |  | ||||||
|         } |  | ||||||
|         ref.invalidate(accountRelationshipProvider(name)); |  | ||||||
|       } catch (err) { |  | ||||||
|         showErrorAlert(err); |  | ||||||
|       } finally { |  | ||||||
|         if (context.mounted) hideLoadingModal(context); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Future<void> directMessageAction() async { |   const _AccountProfileBio({required this.data}); | ||||||
|       if (!account.hasValue) return; |  | ||||||
|       if (accountChat.value != null) { |   @override | ||||||
|         context.pushNamed( |   Widget build(BuildContext context) { | ||||||
|           'chatRoom', |     return Card( | ||||||
|           pathParameters: {'id': accountChat.value!.id}, |       child: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           Text('bio').tr().bold().fontSize(15).padding(bottom: 8), | ||||||
|  |           if (data.profile.bio.isEmpty) | ||||||
|  |             Text('descriptionNone').tr().italic() | ||||||
|  |           else | ||||||
|  |             MarkdownTextContent( | ||||||
|  |               content: data.profile.bio, | ||||||
|  |               linesMargin: EdgeInsets.zero, | ||||||
|  |             ), | ||||||
|  |         ], | ||||||
|  |       ).padding(horizontal: 24, vertical: 20), | ||||||
|     ); |     ); | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       showLoadingModal(context); |  | ||||||
|       try { |  | ||||||
|         final client = ref.watch(apiClientProvider); |  | ||||||
|         final resp = await client.post( |  | ||||||
|           '/sphere/chat/direct', |  | ||||||
|           data: {'related_user_id': account.value!.id}, |  | ||||||
|         ); |  | ||||||
|         final chat = SnChatRoom.fromJson(resp.data); |  | ||||||
|         if (context.mounted) { |  | ||||||
|           context.pushNamed('chatRoom', pathParameters: {'id': chat.id}); |  | ||||||
|         } |  | ||||||
|         ref.invalidate(accountDirectChatProvider(name)); |  | ||||||
|       } catch (err) { |  | ||||||
|         showErrorAlert(err); |  | ||||||
|       } finally { |  | ||||||
|         if (context.mounted) hideLoadingModal(context); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|     List<Widget> buildSubcolumn(SnAccount data) { | class _AccountProfileDetail extends StatelessWidget { | ||||||
|  |   final SnAccount data; | ||||||
|  |  | ||||||
|  |   const _AccountProfileDetail({required this.data}); | ||||||
|  |  | ||||||
|  |   List<Widget> _buildSubcolumn() { | ||||||
|     return [ |     return [ | ||||||
|       Row( |       Row( | ||||||
|         spacing: 6, |         spacing: 6, | ||||||
| @@ -252,90 +196,63 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|           spacing: 6, |           spacing: 6, | ||||||
|           children: [ |           children: [ | ||||||
|             const Icon(Symbols.id_card, size: 17, fill: 1), |             const Icon(Symbols.id_card, size: 17, fill: 1), | ||||||
|               if (data.profile.firstName.isNotEmpty) |             if (data.profile.firstName.isNotEmpty) Text(data.profile.firstName), | ||||||
|                 Text(data.profile.firstName), |  | ||||||
|             if (data.profile.middleName.isNotEmpty) |             if (data.profile.middleName.isNotEmpty) | ||||||
|               Text(data.profile.middleName), |               Text(data.profile.middleName), | ||||||
|             if (data.profile.lastName.isNotEmpty) Text(data.profile.lastName), |             if (data.profile.lastName.isNotEmpty) Text(data.profile.lastName), | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|  |       Tooltip( | ||||||
|  |         message: 'creditsStatus'.tr(), | ||||||
|  |         child: Row( | ||||||
|  |           spacing: 6, | ||||||
|  |           children: [ | ||||||
|  |             Icon(Symbols.star, size: 17, fill: 1).padding(right: 2), | ||||||
|  |             Text('${data.profile.socialCredits.toStringAsFixed(2)} pts'), | ||||||
|  |             Text('·').bold(), | ||||||
|  |             switch (data.profile.socialCreditsLevel) { | ||||||
|  |               -1 => Text('socialCreditsLevelPoor').tr(), | ||||||
|  |               0 => Text('socialCreditsLevelNormal').tr(), | ||||||
|  |               1 => Text('socialCreditsLevelGood').tr(), | ||||||
|  |               2 => Text('socialCreditsLevelExcellent').tr(), | ||||||
|  |               _ => Text('unknown').tr(), | ||||||
|  |             }, | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |       InkWell( | ||||||
|  |         child: Row( | ||||||
|  |           spacing: 6, | ||||||
|  |           children: [ | ||||||
|  |             Icon(Symbols.fingerprint, size: 17, fill: 1).padding(right: 2), | ||||||
|  |             Flexible( | ||||||
|  |               child: Text( | ||||||
|  |                 data.id, | ||||||
|  |                 maxLines: 1, | ||||||
|  |                 overflow: TextOverflow.ellipsis, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |         onTap: () { | ||||||
|  |           Clipboard.setData(ClipboardData(text: data.id)); | ||||||
|  |         }, | ||||||
|  |       ), | ||||||
|     ]; |     ]; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|     final user = ref.watch(userInfoProvider); |   @override | ||||||
|     final isCurrentUser = useMemoized( |   Widget build(BuildContext context) { | ||||||
|       () => user.value?.id == account.value?.id, |     return Card( | ||||||
|       [user, account], |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     Widget accountBasicInfo(SnAccount data) => Padding( |  | ||||||
|       padding: const EdgeInsets.fromLTRB(24, 24, 24, 8), |  | ||||||
|       child: Row( |  | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|         children: [ |  | ||||||
|           ProfilePictureWidget(file: data.profile.picture, radius: 32), |  | ||||||
|           const Gap(20), |  | ||||||
|           Expanded( |  | ||||||
|             child: Column( |  | ||||||
|               crossAxisAlignment: CrossAxisAlignment.stretch, |  | ||||||
|               children: [ |  | ||||||
|                 Row( |  | ||||||
|                   children: [ |  | ||||||
|                     AccountName(account: data, style: TextStyle(fontSize: 20)), |  | ||||||
|                     const Gap(6), |  | ||||||
|                     Flexible( |  | ||||||
|                       child: Text( |  | ||||||
|                         '@${data.name}', |  | ||||||
|                         maxLines: 1, |  | ||||||
|                         overflow: TextOverflow.ellipsis, |  | ||||||
|                       ).fontSize(14).opacity(0.85), |  | ||||||
|                     ), |  | ||||||
|                   ], |  | ||||||
|                 ), |  | ||||||
|                 AccountStatusWidget(uname: name, padding: EdgeInsets.zero), |  | ||||||
|               ], |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|           IconButton( |  | ||||||
|             onPressed: () { |  | ||||||
|               SharePlus.instance.share( |  | ||||||
|                 ShareParams( |  | ||||||
|                   uri: Uri.parse('https://id.solian.app/@${data.name}'), |  | ||||||
|                 ), |  | ||||||
|               ); |  | ||||||
|             }, |  | ||||||
|             icon: const Icon(Symbols.share), |  | ||||||
|           ), |  | ||||||
|         ], |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     Widget accountProfileBio(SnAccount data) => Card( |  | ||||||
|       child: Column( |  | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|         children: [ |  | ||||||
|           Text('bio').tr().bold().fontSize(15).padding(bottom: 8), |  | ||||||
|           if (data.profile.bio.isEmpty) |  | ||||||
|             Text('descriptionNone').tr().italic() |  | ||||||
|           else |  | ||||||
|             MarkdownTextContent( |  | ||||||
|               content: data.profile.bio, |  | ||||||
|               linesMargin: EdgeInsets.zero, |  | ||||||
|             ), |  | ||||||
|         ], |  | ||||||
|       ).padding(horizontal: 24, vertical: 20), |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     Widget accountProfileDetail(SnAccount data) => Card( |  | ||||||
|       child: Column( |       child: Column( | ||||||
|         crossAxisAlignment: CrossAxisAlignment.stretch, |         crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|         spacing: 24, |         spacing: 24, | ||||||
|         children: [ |         children: [ | ||||||
|           if (buildSubcolumn(data).isNotEmpty) |           if (_buildSubcolumn().isNotEmpty) | ||||||
|             Column( |             Column( | ||||||
|               crossAxisAlignment: CrossAxisAlignment.start, |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|               spacing: 2, |               spacing: 2, | ||||||
|               children: buildSubcolumn(data), |               children: _buildSubcolumn(), | ||||||
|             ), |             ), | ||||||
|           if (data.profile.timeZone.isNotEmpty && !kIsWeb) |           if (data.profile.timeZone.isNotEmpty && !kIsWeb) | ||||||
|             Column( |             Column( | ||||||
| @@ -366,8 +283,17 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|         ], |         ], | ||||||
|       ).padding(horizontal: 24, vertical: 16), |       ).padding(horizontal: 24, vertical: 16), | ||||||
|     ); |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|     Widget accountProfileLinks(SnAccount data) => Card( | class _AccountProfileLinks extends StatelessWidget { | ||||||
|  |   final SnAccount data; | ||||||
|  |  | ||||||
|  |   const _AccountProfileLinks({required this.data}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Card( | ||||||
|       child: Column( |       child: Column( | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|         children: [ |         children: [ | ||||||
| @@ -392,9 +318,83 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|         ], |         ], | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|     Widget accountAction(SnAccount data) => Card( | class _AccountPublisherList extends StatelessWidget { | ||||||
|  |   final List<SnPublisher> publishers; | ||||||
|  |  | ||||||
|  |   const _AccountPublisherList({required this.publishers}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     if (publishers.isEmpty) return const SizedBox.shrink(); | ||||||
|  |     return Card( | ||||||
|       child: Column( |       child: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           Text( | ||||||
|  |             'publishers', | ||||||
|  |           ).tr().bold().padding(horizontal: 24, top: 12, bottom: 4), | ||||||
|  |           for (final publisher in publishers) | ||||||
|  |             ListTile( | ||||||
|  |               title: Text(publisher.nick), | ||||||
|  |               subtitle: Text( | ||||||
|  |                 publisher.bio.isNotEmpty | ||||||
|  |                     ? publisher.bio | ||||||
|  |                         .split('\n') | ||||||
|  |                         .where((line) => line.trim().isNotEmpty) | ||||||
|  |                         .join('\n') | ||||||
|  |                     : 'descriptionNone'.tr(), | ||||||
|  |                 maxLines: 3, | ||||||
|  |                 overflow: TextOverflow.ellipsis, | ||||||
|  |               ), | ||||||
|  |               leading: ProfilePictureWidget( | ||||||
|  |                 file: publisher.picture, | ||||||
|  |                 borderRadius: publisher.type == 1 ? 8 : null, | ||||||
|  |               ), | ||||||
|  |               isThreeLine: true, | ||||||
|  |               contentPadding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |               trailing: const Icon(Symbols.chevron_right), | ||||||
|  |               shape: RoundedRectangleBorder( | ||||||
|  |                 borderRadius: const BorderRadius.all(Radius.circular(8)), | ||||||
|  |               ), | ||||||
|  |               onTap: () { | ||||||
|  |                 Navigator.pop(context, true); | ||||||
|  |                 context.pushNamed( | ||||||
|  |                   'publisherProfile', | ||||||
|  |                   pathParameters: {'name': publisher.name}, | ||||||
|  |                 ); | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _AccountAction extends StatelessWidget { | ||||||
|  |   final SnAccount data; | ||||||
|  |   final AsyncValue<SnRelationship?> accountRelationship; | ||||||
|  |   final AsyncValue<SnChatRoom?> accountChat; | ||||||
|  |   final VoidCallback relationshipAction; | ||||||
|  |   final VoidCallback blockAction; | ||||||
|  |   final VoidCallback directMessageAction; | ||||||
|  |  | ||||||
|  |   const _AccountAction({ | ||||||
|  |     required this.data, | ||||||
|  |     required this.accountRelationship, | ||||||
|  |     required this.accountChat, | ||||||
|  |     required this.relationshipAction, | ||||||
|  |     required this.blockAction, | ||||||
|  |     required this.directMessageAction, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Card( | ||||||
|  |       child: Column( | ||||||
|  |         spacing: 8, | ||||||
|         children: [ |         children: [ | ||||||
|           Row( |           Row( | ||||||
|             spacing: 8, |             spacing: 8, | ||||||
| @@ -487,6 +487,7 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                   color: Theme.of(context).colorScheme.onError, |                   color: Theme.of(context).colorScheme.onError, | ||||||
|                 ), |                 ), | ||||||
|                 style: ButtonStyle( |                 style: ButtonStyle( | ||||||
|  |                   visualDensity: VisualDensity.compact, | ||||||
|                   backgroundColor: WidgetStatePropertyAll( |                   backgroundColor: WidgetStatePropertyAll( | ||||||
|                     Theme.of(context).colorScheme.error, |                     Theme.of(context).colorScheme.error, | ||||||
|                   ), |                   ), | ||||||
| @@ -497,10 +498,211 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|         ], |         ], | ||||||
|       ).padding(horizontal: 16, vertical: 12), |       ).padding(horizontal: 16, vertical: 12), | ||||||
|     ); |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<SnAccount> account(Ref ref, String uname) async { | ||||||
|  |   if (uname == 'me') { | ||||||
|  |     final userInfo = ref.watch(userInfoProvider); | ||||||
|  |     if (userInfo.hasValue && userInfo.value != null) { | ||||||
|  |       return userInfo.value!; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   final apiClient = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await apiClient.get("/id/accounts/$uname"); | ||||||
|  |   return SnAccount.fromJson(resp.data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<List<SnAccountBadge>> accountBadges(Ref ref, String uname) async { | ||||||
|  |   final apiClient = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await apiClient.get("/id/accounts/$uname/badges"); | ||||||
|  |   return List<SnAccountBadge>.from( | ||||||
|  |     resp.data.map((x) => SnAccountBadge.fromJson(x)), | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async { | ||||||
|  |   try { | ||||||
|  |     final account = await ref.watch(accountProvider(uname).future); | ||||||
|  |     if (account.profile.background == null) return null; | ||||||
|  |     final palette = await PaletteGenerator.fromImageProvider( | ||||||
|  |       CloudImageWidget.provider( | ||||||
|  |         fileId: account.profile.background!.id, | ||||||
|  |         serverUrl: ref.watch(serverUrlProvider), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |     final dominantColor = palette.dominantColor?.color; | ||||||
|  |     if (dominantColor == null) return null; | ||||||
|  |     return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; | ||||||
|  |   } catch (_) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<SnChatRoom?> accountDirectChat(Ref ref, String uname) async { | ||||||
|  |   final userInfo = ref.watch(userInfoProvider); | ||||||
|  |   if (userInfo.value == null) return null; | ||||||
|  |   final account = await ref.watch(accountProvider(uname).future); | ||||||
|  |   final apiClient = ref.watch(apiClientProvider); | ||||||
|  |   try { | ||||||
|  |     final resp = await apiClient.get("/sphere/chat/direct/${account.id}"); | ||||||
|  |     return SnChatRoom.fromJson(resp.data); | ||||||
|  |   } catch (err) { | ||||||
|  |     if (err is DioException && err.response?.statusCode == 404) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  |     rethrow; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<SnRelationship?> accountRelationship(Ref ref, String uname) async { | ||||||
|  |   final userInfo = ref.watch(userInfoProvider); | ||||||
|  |   if (userInfo.value == null) return null; | ||||||
|  |   final account = await ref.watch(accountProvider(uname).future); | ||||||
|  |   final apiClient = ref.watch(apiClientProvider); | ||||||
|  |   try { | ||||||
|  |     final resp = await apiClient.get("/id/relationships/${account.id}"); | ||||||
|  |     return SnRelationship.fromJson(resp.data); | ||||||
|  |   } catch (err) { | ||||||
|  |     if (err is DioException && err.response?.statusCode == 404) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  |     rethrow; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<SnDeveloper?> accountBotDeveloper(Ref ref, String uname) async { | ||||||
|  |   final account = await ref.watch(accountProvider(uname).future); | ||||||
|  |   if (account.automatedId == null) return null; | ||||||
|  |   final apiClient = ref.watch(apiClientProvider); | ||||||
|  |   try { | ||||||
|  |     final resp = await apiClient.get( | ||||||
|  |       "/develop/bots/${account.automatedId}/developer", | ||||||
|  |     ); | ||||||
|  |     return SnDeveloper.fromJson(resp.data); | ||||||
|  |   } catch (err) { | ||||||
|  |     if (err is DioException && err.response?.statusCode == 404) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  |     rethrow; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<List<SnPublisher>> accountPublishers(Ref ref, String id) async { | ||||||
|  |   final apiClient = ref.watch(apiClientProvider); | ||||||
|  |   try { | ||||||
|  |     final resp = await apiClient.get('/sphere/publishers/of/$id'); | ||||||
|  |     return resp.data | ||||||
|  |         .map((e) => SnPublisher.fromJson(e)) | ||||||
|  |         .cast<SnPublisher>() | ||||||
|  |         .toList(); | ||||||
|  |   } catch (err) { | ||||||
|  |     return []; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class AccountProfileScreen extends HookConsumerWidget { | ||||||
|  |   final String name; | ||||||
|  |   const AccountProfileScreen({super.key, required this.name}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final now = DateTime.now(); | ||||||
|  |  | ||||||
|  |     final account = ref.watch(accountProvider(name)); | ||||||
|  |     final accountEvents = ref.watch( | ||||||
|  |       eventCalendarProvider( | ||||||
|  |         EventCalendarQuery(uname: name, year: now.year, month: now.month), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |     final accountChat = ref.watch(accountDirectChatProvider(name)); | ||||||
|  |     final accountRelationship = ref.watch(accountRelationshipProvider(name)); | ||||||
|  |     final accountDeveloper = ref.watch(accountBotDeveloperProvider(name)); | ||||||
|  |  | ||||||
|  |     final appbarColor = ref.watch(accountAppbarForcegroundColorProvider(name)); | ||||||
|  |  | ||||||
|  |     final appbarShadow = Shadow( | ||||||
|  |       color: appbarColor.value?.invert ?? Colors.transparent, | ||||||
|  |       blurRadius: 5.0, | ||||||
|  |       offset: Offset(1.0, 1.0), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     Future<void> relationshipAction() async { | ||||||
|  |       if (accountRelationship.value != null) return; | ||||||
|  |       showLoadingModal(context); | ||||||
|  |       try { | ||||||
|  |         final client = ref.watch(apiClientProvider); | ||||||
|  |         await client.post('/id/relationships/${account.value!.id}/friends'); | ||||||
|  |         ref.invalidate(accountRelationshipProvider(name)); | ||||||
|  |       } catch (err) { | ||||||
|  |         showErrorAlert(err); | ||||||
|  |       } finally { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Future<void> blockAction() async { | ||||||
|  |       showLoadingModal(context); | ||||||
|  |       try { | ||||||
|  |         final client = ref.watch(apiClientProvider); | ||||||
|  |         if (accountRelationship.value == null) { | ||||||
|  |           await client.post('/id/relationships/${account.value!.id}/block'); | ||||||
|  |         } else { | ||||||
|  |           await client.delete('/id/relationships/${account.value!.id}/block'); | ||||||
|  |         } | ||||||
|  |         ref.invalidate(accountRelationshipProvider(name)); | ||||||
|  |       } catch (err) { | ||||||
|  |         showErrorAlert(err); | ||||||
|  |       } finally { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Future<void> directMessageAction() async { | ||||||
|  |       if (!account.hasValue) return; | ||||||
|  |       if (accountChat.value != null) { | ||||||
|  |         context.pushNamed( | ||||||
|  |           'chatRoom', | ||||||
|  |           pathParameters: {'id': accountChat.value!.id}, | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       showLoadingModal(context); | ||||||
|  |       try { | ||||||
|  |         final client = ref.watch(apiClientProvider); | ||||||
|  |         final resp = await client.post( | ||||||
|  |           '/sphere/chat/direct', | ||||||
|  |           data: {'related_user_id': account.value!.id}, | ||||||
|  |         ); | ||||||
|  |         final chat = SnChatRoom.fromJson(resp.data); | ||||||
|  |         if (context.mounted) { | ||||||
|  |           context.pushNamed('chatRoom', pathParameters: {'id': chat.id}); | ||||||
|  |         } | ||||||
|  |         ref.invalidate(accountDirectChatProvider(name)); | ||||||
|  |       } catch (err) { | ||||||
|  |         showErrorAlert(err); | ||||||
|  |       } finally { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     final user = ref.watch(userInfoProvider); | ||||||
|  |     final isCurrentUser = useMemoized( | ||||||
|  |       () => user.value?.id == account.value?.id, | ||||||
|  |       [user, account], | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     return account.when( |     return account.when( | ||||||
|       data: |       data: (data) { | ||||||
|           (data) => AppScaffold( |         final accountPublishers = ref.watch(accountPublishersProvider(data.id)); | ||||||
|  |         return AppScaffold( | ||||||
|           isNoBackground: false, |           isNoBackground: false, | ||||||
|           appBar: |           appBar: | ||||||
|               isWideScreen(context) |               isWideScreen(context) | ||||||
| @@ -531,9 +733,7 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                             style: TextStyle( |                             style: TextStyle( | ||||||
|                               color: |                               color: | ||||||
|                                   appbarColor.value ?? |                                   appbarColor.value ?? | ||||||
|                                     Theme.of( |                                   Theme.of(context).appBarTheme.foregroundColor, | ||||||
|                                       context, |  | ||||||
|                                     ).appBarTheme.foregroundColor, |  | ||||||
|                               shadows: [appbarShadow], |                               shadows: [appbarShadow], | ||||||
|                             ), |                             ), | ||||||
|                           ), |                           ), | ||||||
| @@ -549,7 +749,13 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                       Flexible( |                       Flexible( | ||||||
|                         child: CustomScrollView( |                         child: CustomScrollView( | ||||||
|                           slivers: [ |                           slivers: [ | ||||||
|                               SliverToBoxAdapter(child: accountBasicInfo(data)), |                             SliverToBoxAdapter( | ||||||
|  |                               child: _AccountBasicInfo( | ||||||
|  |                                 data: data, | ||||||
|  |                                 uname: name, | ||||||
|  |                                 accountDeveloper: accountDeveloper, | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|                             if (data.badges.isNotEmpty) |                             if (data.badges.isNotEmpty) | ||||||
|                               SliverToBoxAdapter( |                               SliverToBoxAdapter( | ||||||
|                                 child: Card( |                                 child: Card( | ||||||
| @@ -578,14 +784,16 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                               ).padding(horizontal: 4, top: 8), |                               ).padding(horizontal: 4, top: 8), | ||||||
|                             ), |                             ), | ||||||
|                             SliverToBoxAdapter( |                             SliverToBoxAdapter( | ||||||
|                                 child: accountProfileBio(data).padding(top: 4), |                               child: _AccountProfileBio( | ||||||
|  |                                 data: data, | ||||||
|  |                               ).padding(top: 4), | ||||||
|                             ), |                             ), | ||||||
|                             if (data.profile.links.isNotEmpty) |                             if (data.profile.links.isNotEmpty) | ||||||
|                               SliverToBoxAdapter( |                               SliverToBoxAdapter( | ||||||
|                                   child: accountProfileLinks(data), |                                 child: _AccountProfileLinks(data: data), | ||||||
|                               ), |                               ), | ||||||
|                             SliverToBoxAdapter( |                             SliverToBoxAdapter( | ||||||
|                                 child: accountProfileDetail(data), |                               child: _AccountProfileDetail(data: data), | ||||||
|                             ), |                             ), | ||||||
|                           ], |                           ], | ||||||
|                         ), |                         ), | ||||||
| @@ -594,8 +802,22 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                         child: CustomScrollView( |                         child: CustomScrollView( | ||||||
|                           slivers: [ |                           slivers: [ | ||||||
|                             SliverGap(24), |                             SliverGap(24), | ||||||
|  |                             SliverToBoxAdapter( | ||||||
|  |                               child: _AccountPublisherList( | ||||||
|  |                                 publishers: accountPublishers.value ?? [], | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|                             if (user.value != null && !isCurrentUser) |                             if (user.value != null && !isCurrentUser) | ||||||
|                                 SliverToBoxAdapter(child: accountAction(data)), |                               SliverToBoxAdapter( | ||||||
|  |                                 child: _AccountAction( | ||||||
|  |                                   data: data, | ||||||
|  |                                   accountRelationship: accountRelationship, | ||||||
|  |                                   accountChat: accountChat, | ||||||
|  |                                   relationshipAction: relationshipAction, | ||||||
|  |                                   blockAction: blockAction, | ||||||
|  |                                   directMessageAction: directMessageAction, | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|                             SliverToBoxAdapter( |                             SliverToBoxAdapter( | ||||||
|                               child: Card( |                               child: Card( | ||||||
|                                 child: FortuneGraphWidget( |                                 child: FortuneGraphWidget( | ||||||
| @@ -651,7 +873,13 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                           ], |                           ], | ||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|                         SliverToBoxAdapter(child: accountBasicInfo(data)), |                       SliverToBoxAdapter( | ||||||
|  |                         child: _AccountBasicInfo( | ||||||
|  |                           data: data, | ||||||
|  |                           uname: name, | ||||||
|  |                           accountDeveloper: accountDeveloper, | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|                       if (data.badges.isNotEmpty) |                       if (data.badges.isNotEmpty) | ||||||
|                         SliverToBoxAdapter( |                         SliverToBoxAdapter( | ||||||
|                           child: Card( |                           child: Card( | ||||||
| @@ -678,22 +906,36 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|                       SliverToBoxAdapter( |                       SliverToBoxAdapter( | ||||||
|                           child: accountProfileBio(data).padding(horizontal: 4), |                         child: _AccountProfileBio( | ||||||
|  |                           data: data, | ||||||
|  |                         ).padding(horizontal: 4), | ||||||
|                       ), |                       ), | ||||||
|                       if (data.profile.links.isNotEmpty) |                       if (data.profile.links.isNotEmpty) | ||||||
|                         SliverToBoxAdapter( |                         SliverToBoxAdapter( | ||||||
|                             child: accountProfileLinks( |                           child: _AccountProfileLinks( | ||||||
|                               data, |                             data: data, | ||||||
|                           ).padding(horizontal: 4), |                           ).padding(horizontal: 4), | ||||||
|                         ), |                         ), | ||||||
|                       SliverToBoxAdapter( |                       SliverToBoxAdapter( | ||||||
|                           child: accountProfileDetail( |                         child: _AccountPublisherList( | ||||||
|                             data, |                           publishers: accountPublishers.value ?? [], | ||||||
|  |                         ).padding(horizontal: 4), | ||||||
|  |                       ), | ||||||
|  |                       SliverToBoxAdapter( | ||||||
|  |                         child: _AccountProfileDetail( | ||||||
|  |                           data: data, | ||||||
|                         ).padding(horizontal: 4), |                         ).padding(horizontal: 4), | ||||||
|                       ), |                       ), | ||||||
|                       if (user.value != null && !isCurrentUser) |                       if (user.value != null && !isCurrentUser) | ||||||
|                         SliverToBoxAdapter( |                         SliverToBoxAdapter( | ||||||
|                             child: accountAction(data).padding(horizontal: 4), |                           child: _AccountAction( | ||||||
|  |                             data: data, | ||||||
|  |                             accountRelationship: accountRelationship, | ||||||
|  |                             accountChat: accountChat, | ||||||
|  |                             relationshipAction: relationshipAction, | ||||||
|  |                             blockAction: blockAction, | ||||||
|  |                             directMessageAction: directMessageAction, | ||||||
|  |                           ).padding(horizontal: 4), | ||||||
|                         ), |                         ), | ||||||
|                       SliverToBoxAdapter( |                       SliverToBoxAdapter( | ||||||
|                         child: Card( |                         child: Card( | ||||||
| @@ -705,7 +947,8 @@ class AccountProfileScreen extends HookConsumerWidget { | |||||||
|                       ), |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ), |                   ), | ||||||
|           ), |         ); | ||||||
|  |       }, | ||||||
|       error: |       error: | ||||||
|           (error, stackTrace) => AppScaffold( |           (error, stackTrace) => AppScaffold( | ||||||
|             appBar: AppBar(leading: const PageBackButton()), |             appBar: AppBar(leading: const PageBackButton()), | ||||||
|   | |||||||
| @@ -639,5 +639,250 @@ class _AccountRelationshipProviderElement | |||||||
|   String get uname => (origin as AccountRelationshipProvider).uname; |   String get uname => (origin as AccountRelationshipProvider).uname; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | String _$accountBotDeveloperHash() => | ||||||
|  |     r'673534770640a8cf1484ea0af0f4d0ef283ef157'; | ||||||
|  |  | ||||||
|  | /// See also [accountBotDeveloper]. | ||||||
|  | @ProviderFor(accountBotDeveloper) | ||||||
|  | const accountBotDeveloperProvider = AccountBotDeveloperFamily(); | ||||||
|  |  | ||||||
|  | /// See also [accountBotDeveloper]. | ||||||
|  | class AccountBotDeveloperFamily extends Family<AsyncValue<SnDeveloper?>> { | ||||||
|  |   /// See also [accountBotDeveloper]. | ||||||
|  |   const AccountBotDeveloperFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [accountBotDeveloper]. | ||||||
|  |   AccountBotDeveloperProvider call(String uname) { | ||||||
|  |     return AccountBotDeveloperProvider(uname); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AccountBotDeveloperProvider getProviderOverride( | ||||||
|  |     covariant AccountBotDeveloperProvider provider, | ||||||
|  |   ) { | ||||||
|  |     return call(provider.uname); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||||
|  |       _allTransitiveDependencies; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String? get name => r'accountBotDeveloperProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [accountBotDeveloper]. | ||||||
|  | class AccountBotDeveloperProvider | ||||||
|  |     extends AutoDisposeFutureProvider<SnDeveloper?> { | ||||||
|  |   /// See also [accountBotDeveloper]. | ||||||
|  |   AccountBotDeveloperProvider(String uname) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => accountBotDeveloper(ref as AccountBotDeveloperRef, uname), | ||||||
|  |         from: accountBotDeveloperProvider, | ||||||
|  |         name: r'accountBotDeveloperProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$accountBotDeveloperHash, | ||||||
|  |         dependencies: AccountBotDeveloperFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: | ||||||
|  |             AccountBotDeveloperFamily._allTransitiveDependencies, | ||||||
|  |         uname: uname, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   AccountBotDeveloperProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.uname, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String uname; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<SnDeveloper?> Function(AccountBotDeveloperRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: AccountBotDeveloperProvider._internal( | ||||||
|  |         (ref) => create(ref as AccountBotDeveloperRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         uname: uname, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<SnDeveloper?> createElement() { | ||||||
|  |     return _AccountBotDeveloperProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is AccountBotDeveloperProvider && other.uname == uname; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, uname.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin AccountBotDeveloperRef on AutoDisposeFutureProviderRef<SnDeveloper?> { | ||||||
|  |   /// The parameter `uname` of this provider. | ||||||
|  |   String get uname; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _AccountBotDeveloperProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<SnDeveloper?> | ||||||
|  |     with AccountBotDeveloperRef { | ||||||
|  |   _AccountBotDeveloperProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get uname => (origin as AccountBotDeveloperProvider).uname; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | String _$accountPublishersHash() => r'25f5695b4a5154163d77f1769876d826bf736609'; | ||||||
|  |  | ||||||
|  | /// See also [accountPublishers]. | ||||||
|  | @ProviderFor(accountPublishers) | ||||||
|  | const accountPublishersProvider = AccountPublishersFamily(); | ||||||
|  |  | ||||||
|  | /// See also [accountPublishers]. | ||||||
|  | class AccountPublishersFamily extends Family<AsyncValue<List<SnPublisher>>> { | ||||||
|  |   /// See also [accountPublishers]. | ||||||
|  |   const AccountPublishersFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [accountPublishers]. | ||||||
|  |   AccountPublishersProvider call(String id) { | ||||||
|  |     return AccountPublishersProvider(id); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AccountPublishersProvider getProviderOverride( | ||||||
|  |     covariant AccountPublishersProvider provider, | ||||||
|  |   ) { | ||||||
|  |     return call(provider.id); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||||
|  |       _allTransitiveDependencies; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String? get name => r'accountPublishersProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [accountPublishers]. | ||||||
|  | class AccountPublishersProvider | ||||||
|  |     extends AutoDisposeFutureProvider<List<SnPublisher>> { | ||||||
|  |   /// See also [accountPublishers]. | ||||||
|  |   AccountPublishersProvider(String id) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => accountPublishers(ref as AccountPublishersRef, id), | ||||||
|  |         from: accountPublishersProvider, | ||||||
|  |         name: r'accountPublishersProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$accountPublishersHash, | ||||||
|  |         dependencies: AccountPublishersFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: | ||||||
|  |             AccountPublishersFamily._allTransitiveDependencies, | ||||||
|  |         id: id, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   AccountPublishersProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.id, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String id; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<List<SnPublisher>> Function(AccountPublishersRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: AccountPublishersProvider._internal( | ||||||
|  |         (ref) => create(ref as AccountPublishersRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         id: id, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<List<SnPublisher>> createElement() { | ||||||
|  |     return _AccountPublishersProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is AccountPublishersProvider && other.id == id; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, id.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin AccountPublishersRef on AutoDisposeFutureProviderRef<List<SnPublisher>> { | ||||||
|  |   /// The parameter `id` of this provider. | ||||||
|  |   String get id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _AccountPublishersProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<List<SnPublisher>> | ||||||
|  |     with AccountPublishersRef { | ||||||
|  |   _AccountPublishersProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get id => (origin as AccountPublishersProvider).id; | ||||||
|  | } | ||||||
|  |  | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
| // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; | |||||||
| import 'package:flutter_hooks/flutter_hooks.dart'; | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/pods/userinfo.dart'; | import 'package:island/pods/userinfo.dart'; | ||||||
|  | import 'package:island/widgets/account/account_pfc.dart'; | ||||||
| import 'package:island/widgets/account/account_picker.dart'; | import 'package:island/widgets/account/account_picker.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| @@ -99,7 +100,10 @@ class RelationshipListTile extends StatelessWidget { | |||||||
|  |  | ||||||
|     return ListTile( |     return ListTile( | ||||||
|       contentPadding: const EdgeInsets.only(left: 16, right: 12), |       contentPadding: const EdgeInsets.only(left: 16, right: 12), | ||||||
|       leading: ProfilePictureWidget(fileId: account.profile.picture?.id), |       leading: AccountPfcGestureDetector( | ||||||
|  |         uname: account.name, | ||||||
|  |         child: ProfilePictureWidget(fileId: account.profile.picture?.id), | ||||||
|  |       ), | ||||||
|       title: Row( |       title: Row( | ||||||
|         spacing: 6, |         spacing: 6, | ||||||
|         children: [ |         children: [ | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; | |||||||
| import 'package:gap/gap.dart'; | import 'package:gap/gap.dart'; | ||||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/screens/account/me/update.dart'; | import 'package:island/screens/account/me/profile_update.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:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|   | |||||||
| @@ -42,6 +42,22 @@ final Map<int, (String, String, IconData)> kFactorTypes = { | |||||||
|   4: ('authFactorPin', 'authFactorPinDescription', Symbols.nest_secure_alarm), |   4: ('authFactorPin', 'authFactorPinDescription', Symbols.nest_secure_alarm), | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | Future<String?> getDeviceName() async { | ||||||
|  |   if (kIsWeb) return null; | ||||||
|  |   String? name; | ||||||
|  |   if (Platform.isIOS) { | ||||||
|  |     final deviceInfo = await DeviceInfoPlugin().iosInfo; | ||||||
|  |     name = deviceInfo.name; | ||||||
|  |   } else if (Platform.isAndroid) { | ||||||
|  |     final deviceInfo = await DeviceInfoPlugin().androidInfo; | ||||||
|  |     name = deviceInfo.name; | ||||||
|  |   } else if (Platform.isWindows) { | ||||||
|  |     final deviceInfo = await DeviceInfoPlugin().windowsInfo; | ||||||
|  |     name = deviceInfo.computerName; | ||||||
|  |   } | ||||||
|  |   return name; | ||||||
|  | } | ||||||
|  |  | ||||||
| class LoginScreen extends HookConsumerWidget { | class LoginScreen extends HookConsumerWidget { | ||||||
|   const LoginScreen({super.key}); |   const LoginScreen({super.key}); | ||||||
|  |  | ||||||
| @@ -198,28 +214,6 @@ class _LoginCheckScreen extends HookConsumerWidget { | |||||||
|         wsNotifier.connect(); |         wsNotifier.connect(); | ||||||
|         if (context.mounted) Navigator.pop(context, true); |         if (context.mounted) Navigator.pop(context, true); | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|       // Update the sessions' device name is available |  | ||||||
|       if (!kIsWeb) { |  | ||||||
|         String? name; |  | ||||||
|         if (Platform.isIOS) { |  | ||||||
|           final deviceInfo = await DeviceInfoPlugin().iosInfo; |  | ||||||
|           name = deviceInfo.name; |  | ||||||
|         } else if (Platform.isAndroid) { |  | ||||||
|           final deviceInfo = await DeviceInfoPlugin().androidInfo; |  | ||||||
|           name = deviceInfo.name; |  | ||||||
|         } else if (Platform.isWindows) { |  | ||||||
|           final deviceInfo = await DeviceInfoPlugin().windowsInfo; |  | ||||||
|           name = deviceInfo.computerName; |  | ||||||
|         } |  | ||||||
|         if (name != null) { |  | ||||||
|           final client = ref.watch(apiClientProvider); |  | ||||||
|           await client.patch( |  | ||||||
|             '/id/accounts/me/sessions/current/label', |  | ||||||
|             data: jsonEncode(name), |  | ||||||
|           ); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     useEffect(() { |     useEffect(() { | ||||||
| @@ -578,6 +572,7 @@ class _LoginLookupScreen extends HookConsumerWidget { | |||||||
|           data: { |           data: { | ||||||
|             'account': uname, |             'account': uname, | ||||||
|             'device_id': await getUdid(), |             'device_id': await getUdid(), | ||||||
|  |             'device_name': await getDeviceName(), | ||||||
|             'platform': |             'platform': | ||||||
|                 kIsWeb |                 kIsWeb | ||||||
|                     ? 1 |                     ? 1 | ||||||
| @@ -628,6 +623,7 @@ class _LoginLookupScreen extends HookConsumerWidget { | |||||||
|             'identity_token': credential.identityToken!, |             'identity_token': credential.identityToken!, | ||||||
|             'authorization_code': credential.authorizationCode, |             'authorization_code': credential.authorizationCode, | ||||||
|             'device_id': await getUdid(), |             'device_id': await getUdid(), | ||||||
|  |             'device_name': await getDeviceName(), | ||||||
|           }, |           }, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
| @@ -704,6 +700,7 @@ class _LoginLookupScreen extends HookConsumerWidget { | |||||||
|           onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), |           onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||||
|           onSubmitted: isBusy.value ? null : (_) => performNewTicket(), |           onSubmitted: isBusy.value ? null : (_) => performNewTicket(), | ||||||
|         ).padding(horizontal: 7), |         ).padding(horizontal: 7), | ||||||
|  |         if (!kIsWeb) | ||||||
|           Row( |           Row( | ||||||
|             spacing: 6, |             spacing: 6, | ||||||
|             crossAxisAlignment: CrossAxisAlignment.center, |             crossAxisAlignment: CrossAxisAlignment.center, | ||||||
| @@ -742,7 +739,9 @@ class _LoginLookupScreen extends HookConsumerWidget { | |||||||
|                 tooltip: 'Apple Account', |                 tooltip: 'Apple Account', | ||||||
|               ), |               ), | ||||||
|             ], |             ], | ||||||
|         ).padding(horizontal: 8, vertical: 8), |           ).padding(horizontal: 8, vertical: 8) | ||||||
|  |         else | ||||||
|  |           const Gap(12), | ||||||
|         Row( |         Row( | ||||||
|           mainAxisAlignment: MainAxisAlignment.spaceBetween, |           mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|           children: [ |           children: [ | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ import 'package:island/widgets/alert.dart'; | |||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/content/cloud_files.dart'; | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
| import 'package:island/widgets/content/sheet.dart'; | import 'package:island/widgets/content/sheet.dart'; | ||||||
| import 'package:island/widgets/realms/selection_dropdown.dart'; | import 'package:island/widgets/realm/realm_selection_dropdown.dart'; | ||||||
| import 'package:island/widgets/response.dart'; | import 'package:island/widgets/response.dart'; | ||||||
| import 'package:island/screens/tabs.dart'; | import 'package:island/screens/tabs.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| @@ -79,16 +79,21 @@ class ChatRoomListTile extends HookConsumerWidget { | |||||||
|                     color: Theme.of(context).colorScheme.primary, |                     color: Theme.of(context).colorScheme.primary, | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|  |               if (data.lastMessage == null) | ||||||
|  |                 Text(room.description ?? 'descriptionNone'.tr(), maxLines: 1) | ||||||
|  |               else | ||||||
|                 Row( |                 Row( | ||||||
|  |                   spacing: 4, | ||||||
|                   children: [ |                   children: [ | ||||||
|                   Text( |                     Badge( | ||||||
|                     '${data.lastMessage.sender.account.name}: ', |                       label: Text(data.lastMessage!.sender.account.nick), | ||||||
|                     style: Theme.of(context).textTheme.bodySmall, |                       textColor: Theme.of(context).colorScheme.onPrimary, | ||||||
|  |                       backgroundColor: Theme.of(context).colorScheme.primary, | ||||||
|                     ), |                     ), | ||||||
|                     Expanded( |                     Expanded( | ||||||
|                       child: Text( |                       child: Text( | ||||||
|                       (data.lastMessage.content?.isNotEmpty ?? false) |                         (data.lastMessage!.content?.isNotEmpty ?? false) | ||||||
|                           ? data.lastMessage.content! |                             ? data.lastMessage!.content! | ||||||
|                             : 'messageNone'.tr(), |                             : 'messageNone'.tr(), | ||||||
|                         maxLines: 1, |                         maxLines: 1, | ||||||
|                         overflow: TextOverflow.ellipsis, |                         overflow: TextOverflow.ellipsis, | ||||||
| @@ -98,7 +103,9 @@ class ChatRoomListTile extends HookConsumerWidget { | |||||||
|                     Align( |                     Align( | ||||||
|                       alignment: Alignment.centerRight, |                       alignment: Alignment.centerRight, | ||||||
|                       child: Text( |                       child: Text( | ||||||
|                       RelativeTime(context).format(data.lastMessage.createdAt), |                         RelativeTime( | ||||||
|  |                           context, | ||||||
|  |                         ).format(data.lastMessage!.createdAt), | ||||||
|                         style: Theme.of(context).textTheme.bodySmall, |                         style: Theme.of(context).textTheme.bodySmall, | ||||||
|                       ), |                       ), | ||||||
|                     ), |                     ), | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -6,7 +6,7 @@ part of 'room.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$messagesNotifierHash() => r'afc4d43f4948ec571118cef0321838a6cefc89c0'; | String _$messagesNotifierHash() => r'fc3b66dfb8dd3fc55d142dae5c5e7bdc67eca5d4'; | ||||||
|  |  | ||||||
| /// Copied from Dart SDK | /// Copied from Dart SDK | ||||||
| class _SystemHash { | class _SystemHash { | ||||||
|   | |||||||
| @@ -9,7 +9,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; | |||||||
| import 'package:island/models/chat.dart'; | import 'package:island/models/chat.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/screens/chat/chat.dart'; | import 'package:island/screens/chat/chat.dart'; | ||||||
|  | import 'package:island/widgets/account/account_pfc.dart'; | ||||||
| import 'package:island/widgets/account/account_picker.dart'; | import 'package:island/widgets/account/account_picker.dart'; | ||||||
|  | import 'package:island/widgets/account/status.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/content/cloud_files.dart'; | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
| @@ -18,10 +20,17 @@ import 'package:material_symbols_icons/symbols.dart'; | |||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  | import 'package:island/pods/database.dart'; | ||||||
|  |  | ||||||
| part 'room_detail.freezed.dart'; | part 'room_detail.freezed.dart'; | ||||||
| part 'room_detail.g.dart'; | part 'room_detail.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<int> totalMessagesCount(Ref ref, String roomId) async { | ||||||
|  |   final database = ref.watch(databaseProvider); | ||||||
|  |   return database.getTotalMessagesForRoom(roomId); | ||||||
|  | } | ||||||
|  |  | ||||||
| class ChatDetailScreen extends HookConsumerWidget { | class ChatDetailScreen extends HookConsumerWidget { | ||||||
|   final String id; |   final String id; | ||||||
|   const ChatDetailScreen({super.key, required this.id}); |   const ChatDetailScreen({super.key, required this.id}); | ||||||
| @@ -30,6 +39,7 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final roomState = ref.watch(chatroomProvider(id)); |     final roomState = ref.watch(chatroomProvider(id)); | ||||||
|     final roomIdentity = ref.watch(chatroomIdentityProvider(id)); |     final roomIdentity = ref.watch(chatroomIdentityProvider(id)); | ||||||
|  |     final totalMessages = ref.watch(totalMessagesCountProvider(id)); | ||||||
|  |  | ||||||
|     const kNotifyLevelText = [ |     const kNotifyLevelText = [ | ||||||
|       'chatNotifyLevelAll', |       'chatNotifyLevelAll', | ||||||
| @@ -130,7 +140,7 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|                   const Text('chatBreakDescription').tr(), |                   const Text('chatBreakDescription').tr(), | ||||||
|                   const Gap(16), |                   const Gap(16), | ||||||
|                   ListTile( |                   ListTile( | ||||||
|                     title: const Text('Clear').tr(), |                     title: const Text('chatBreakClearButton').tr(), | ||||||
|                     subtitle: const Text('chatBreakClear').tr(), |                     subtitle: const Text('chatBreakClear').tr(), | ||||||
|                     leading: const Icon(Icons.notifications_active), |                     leading: const Icon(Icons.notifications_active), | ||||||
|                     onTap: () { |                     onTap: () { | ||||||
| @@ -142,8 +152,10 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
|                   ListTile( |                   ListTile( | ||||||
|                     title: const Text('5m'), |                     title: const Text('chatBreak5m').tr(), | ||||||
|                     subtitle: const Text('chatBreakHour').tr(args: ['5m']), |                     subtitle: const Text( | ||||||
|  |                       'chatBreakHour', | ||||||
|  |                     ).tr(args: ['chatBreak5m'.tr()]), | ||||||
|                     leading: const Icon(Symbols.circle), |                     leading: const Icon(Symbols.circle), | ||||||
|                     onTap: () { |                     onTap: () { | ||||||
|                       setChatBreak(now.add(const Duration(minutes: 5))); |                       setChatBreak(now.add(const Duration(minutes: 5))); | ||||||
| @@ -154,8 +166,10 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
|                   ListTile( |                   ListTile( | ||||||
|                     title: const Text('10m'), |                     title: const Text('chatBreak10m').tr(), | ||||||
|                     subtitle: const Text('chatBreakHour').tr(args: ['10m']), |                     subtitle: const Text( | ||||||
|  |                       'chatBreakHour', | ||||||
|  |                     ).tr(args: ['chatBreak10m'.tr()]), | ||||||
|                     leading: const Icon(Symbols.circle), |                     leading: const Icon(Symbols.circle), | ||||||
|                     onTap: () { |                     onTap: () { | ||||||
|                       setChatBreak(now.add(const Duration(minutes: 10))); |                       setChatBreak(now.add(const Duration(minutes: 10))); | ||||||
| @@ -166,8 +180,10 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
|                   ListTile( |                   ListTile( | ||||||
|                     title: const Text('15m'), |                     title: const Text('chatBreak15m').tr(), | ||||||
|                     subtitle: const Text('chatBreakHour').tr(args: ['15m']), |                     subtitle: const Text( | ||||||
|  |                       'chatBreakHour', | ||||||
|  |                     ).tr(args: ['chatBreak15m'.tr()]), | ||||||
|                     leading: const Icon(Symbols.timer_3), |                     leading: const Icon(Symbols.timer_3), | ||||||
|                     onTap: () { |                     onTap: () { | ||||||
|                       setChatBreak(now.add(const Duration(minutes: 15))); |                       setChatBreak(now.add(const Duration(minutes: 15))); | ||||||
| @@ -178,8 +194,10 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
|                   ListTile( |                   ListTile( | ||||||
|                     title: const Text('30m'), |                     title: const Text('chatBreak30m').tr(), | ||||||
|                     subtitle: const Text('chatBreakHour').tr(args: ['30m']), |                     subtitle: const Text( | ||||||
|  |                       'chatBreakHour', | ||||||
|  |                     ).tr(args: ['chatBreak30m'.tr()]), | ||||||
|                     leading: const Icon(Symbols.timer), |                     leading: const Icon(Symbols.timer), | ||||||
|                     onTap: () { |                     onTap: () { | ||||||
|                       setChatBreak(now.add(const Duration(minutes: 30))); |                       setChatBreak(now.add(const Duration(minutes: 30))); | ||||||
| @@ -193,8 +211,8 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|                   TextField( |                   TextField( | ||||||
|                     controller: durationController, |                     controller: durationController, | ||||||
|                     decoration: InputDecoration( |                     decoration: InputDecoration( | ||||||
|                       labelText: 'Custom (minutes)'.tr(), |                       labelText: 'chatBreakCustomMinutes'.tr(), | ||||||
|                       hintText: 'Enter minutes'.tr(), |                       hintText: 'chatBreakEnterMinutes'.tr(), | ||||||
|                       border: const OutlineInputBorder(), |                       border: const OutlineInputBorder(), | ||||||
|                       suffixIcon: IconButton( |                       suffixIcon: IconButton( | ||||||
|                         icon: const Icon(Icons.check), |                         icon: const Icon(Icons.check), | ||||||
| @@ -237,7 +255,10 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|     return AppScaffold( |     return AppScaffold( | ||||||
|       body: roomState.when( |       body: roomState.when( | ||||||
|         loading: () => const Center(child: CircularProgressIndicator()), |         loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|         error: (error, _) => Center(child: Text('Error: $error')), |         error: | ||||||
|  |             (error, _) => Center( | ||||||
|  |               child: Text('errorGeneric'.tr(args: [error.toString()])), | ||||||
|  |             ), | ||||||
|         data: |         data: | ||||||
|             (currentRoom) => CustomScrollView( |             (currentRoom) => CustomScrollView( | ||||||
|               slivers: [ |               slivers: [ | ||||||
| @@ -357,6 +378,36 @@ class ChatDetailScreen extends HookConsumerWidget { | |||||||
|                                           : const Text('chatBreakNone').tr(), |                                           : const Text('chatBreakNone').tr(), | ||||||
|                                   onTap: () => showChatBreakDialog(), |                                   onTap: () => showChatBreakDialog(), | ||||||
|                                 ), |                                 ), | ||||||
|  |                                 ListTile( | ||||||
|  |                                   contentPadding: EdgeInsets.symmetric( | ||||||
|  |                                     horizontal: 24, | ||||||
|  |                                   ), | ||||||
|  |                                   leading: const Icon(Icons.search), | ||||||
|  |                                   trailing: const Icon(Symbols.chevron_right), | ||||||
|  |                                   title: const Text('searchMessages').tr(), | ||||||
|  |                                   subtitle: totalMessages.when( | ||||||
|  |                                     data: | ||||||
|  |                                         (count) => Text( | ||||||
|  |                                           'messagesCount'.tr( | ||||||
|  |                                             args: [count.toString()], | ||||||
|  |                                           ), | ||||||
|  |                                         ), | ||||||
|  |                                     loading: | ||||||
|  |                                         () => const CircularProgressIndicator(), | ||||||
|  |                                     error: | ||||||
|  |                                         (err, stack) => Text( | ||||||
|  |                                           'errorGeneric'.tr( | ||||||
|  |                                             args: [err.toString()], | ||||||
|  |                                           ), | ||||||
|  |                                         ), | ||||||
|  |                                   ), | ||||||
|  |                                   onTap: () { | ||||||
|  |                                     context.pushNamed( | ||||||
|  |                                       'searchMessages', | ||||||
|  |                                       pathParameters: {'id': id}, | ||||||
|  |                                     ); | ||||||
|  |                                   }, | ||||||
|  |                                 ), | ||||||
|                               ], |                               ], | ||||||
|                             ), |                             ), | ||||||
|                         error: (_, _) => const SizedBox.shrink(), |                         error: (_, _) => const SizedBox.shrink(), | ||||||
| @@ -544,7 +595,7 @@ class ChatMemberListNotifier extends _$ChatMemberListNotifier | |||||||
|     final apiClient = ref.watch(apiClientProvider); |     final apiClient = ref.watch(apiClientProvider); | ||||||
|     final response = await apiClient.get( |     final response = await apiClient.get( | ||||||
|       '/sphere/chat/$roomId/members', |       '/sphere/chat/$roomId/members', | ||||||
|       queryParameters: {'offset': offset, 'take': take}, |       queryParameters: {'offset': offset, 'take': take, 'withStatus': true}, | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     final total = int.parse(response.headers.value('X-Total') ?? '0'); |     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||||
| @@ -665,13 +716,18 @@ class _ChatMemberListSheet extends HookConsumerWidget { | |||||||
|                     final member = data.items[index]; |                     final member = data.items[index]; | ||||||
|                     return ListTile( |                     return ListTile( | ||||||
|                       contentPadding: EdgeInsets.only(left: 16, right: 12), |                       contentPadding: EdgeInsets.only(left: 16, right: 12), | ||||||
|                       leading: ProfilePictureWidget( |                       leading: AccountPfcGestureDetector( | ||||||
|  |                         uname: member.account.name, | ||||||
|  |                         child: ProfilePictureWidget( | ||||||
|                           fileId: member.account.profile.picture?.id, |                           fileId: member.account.profile.picture?.id, | ||||||
|                         ), |                         ), | ||||||
|  |                       ), | ||||||
|                       title: Row( |                       title: Row( | ||||||
|                         spacing: 6, |                         spacing: 6, | ||||||
|                         children: [ |                         children: [ | ||||||
|                           Flexible(child: Text(member.account.nick)), |                           Flexible(child: Text(member.account.nick)), | ||||||
|  |                           if (member.status != null) | ||||||
|  |                             AccountStatusLabel(status: member.status!), | ||||||
|                           if (member.joinedAt == null) |                           if (member.joinedAt == null) | ||||||
|                             const Icon(Symbols.pending_actions, size: 20), |                             const Icon(Symbols.pending_actions, size: 20), | ||||||
|                         ], |                         ], | ||||||
| @@ -845,7 +901,7 @@ class _ChatMemberRoleSheet extends HookConsumerWidget { | |||||||
|                     try { |                     try { | ||||||
|                       final newRole = int.parse(roleController.text); |                       final newRole = int.parse(roleController.text); | ||||||
|                       if (newRole < 0 || newRole > 100) { |                       if (newRole < 0 || newRole > 100) { | ||||||
|                         throw 'Role must be between 0 and 100'; |                         throw 'roleValidationHint'.tr(); | ||||||
|                       } |                       } | ||||||
|  |  | ||||||
|                       final apiClient = ref.read(apiClientProvider); |                       final apiClient = ref.read(apiClientProvider); | ||||||
|   | |||||||
| @@ -6,8 +6,8 @@ part of 'room_detail.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$chatMemberListNotifierHash() => | String _$totalMessagesCountHash() => | ||||||
|     r'c8fbf4b95df6dae24b1ba21063e9a43351832974'; |     r'd55f1507aba2acdce5e468c1c2e15dba7640c571'; | ||||||
|  |  | ||||||
| /// Copied from Dart SDK | /// Copied from Dart SDK | ||||||
| class _SystemHash { | class _SystemHash { | ||||||
| @@ -30,6 +30,128 @@ class _SystemHash { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// See also [totalMessagesCount]. | ||||||
|  | @ProviderFor(totalMessagesCount) | ||||||
|  | const totalMessagesCountProvider = TotalMessagesCountFamily(); | ||||||
|  |  | ||||||
|  | /// See also [totalMessagesCount]. | ||||||
|  | class TotalMessagesCountFamily extends Family<AsyncValue<int>> { | ||||||
|  |   /// See also [totalMessagesCount]. | ||||||
|  |   const TotalMessagesCountFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [totalMessagesCount]. | ||||||
|  |   TotalMessagesCountProvider call(String roomId) { | ||||||
|  |     return TotalMessagesCountProvider(roomId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   TotalMessagesCountProvider getProviderOverride( | ||||||
|  |     covariant TotalMessagesCountProvider provider, | ||||||
|  |   ) { | ||||||
|  |     return call(provider.roomId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||||
|  |       _allTransitiveDependencies; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String? get name => r'totalMessagesCountProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [totalMessagesCount]. | ||||||
|  | class TotalMessagesCountProvider extends AutoDisposeFutureProvider<int> { | ||||||
|  |   /// See also [totalMessagesCount]. | ||||||
|  |   TotalMessagesCountProvider(String roomId) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => totalMessagesCount(ref as TotalMessagesCountRef, roomId), | ||||||
|  |         from: totalMessagesCountProvider, | ||||||
|  |         name: r'totalMessagesCountProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$totalMessagesCountHash, | ||||||
|  |         dependencies: TotalMessagesCountFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: | ||||||
|  |             TotalMessagesCountFamily._allTransitiveDependencies, | ||||||
|  |         roomId: roomId, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   TotalMessagesCountProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.roomId, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String roomId; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<int> Function(TotalMessagesCountRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: TotalMessagesCountProvider._internal( | ||||||
|  |         (ref) => create(ref as TotalMessagesCountRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         roomId: roomId, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<int> createElement() { | ||||||
|  |     return _TotalMessagesCountProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is TotalMessagesCountProvider && other.roomId == roomId; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, roomId.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin TotalMessagesCountRef on AutoDisposeFutureProviderRef<int> { | ||||||
|  |   /// The parameter `roomId` of this provider. | ||||||
|  |   String get roomId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _TotalMessagesCountProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<int> | ||||||
|  |     with TotalMessagesCountRef { | ||||||
|  |   _TotalMessagesCountProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get roomId => (origin as TotalMessagesCountProvider).roomId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | String _$chatMemberListNotifierHash() => | ||||||
|  |     r'3ea30150278523e9f6b23f9200ea9a9fbae9c973'; | ||||||
|  |  | ||||||
| abstract class _$ChatMemberListNotifier | abstract class _$ChatMemberListNotifier | ||||||
|     extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnChatMember>> { |     extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnChatMember>> { | ||||||
|   late final String roomId; |   late final String roomId; | ||||||
|   | |||||||
							
								
								
									
										139
									
								
								lib/screens/chat/search_messages_screen.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								lib/screens/chat/search_messages_screen.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/screens/chat/room.dart'; | ||||||
|  | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|  | import 'package:island/widgets/chat/message_item.dart'; | ||||||
|  | import 'package:material_symbols_icons/material_symbols_icons.dart'; | ||||||
|  | import 'package:super_sliver_list/super_sliver_list.dart'; | ||||||
|  |  | ||||||
|  | class SearchMessagesScreen extends HookConsumerWidget { | ||||||
|  |   final String roomId; | ||||||
|  |  | ||||||
|  |   const SearchMessagesScreen({super.key, required this.roomId}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final searchController = useTextEditingController(); | ||||||
|  |     final withLinks = useState(false); | ||||||
|  |     final withAttachments = useState(false); | ||||||
|  |  | ||||||
|  |     final messagesNotifier = ref.read( | ||||||
|  |       messagesNotifierProvider(roomId).notifier, | ||||||
|  |     ); | ||||||
|  |     final messages = ref.watch(messagesNotifierProvider(roomId)); | ||||||
|  |  | ||||||
|  |     useEffect(() { | ||||||
|  |       // Clear search when screen is disposed | ||||||
|  |       return () { | ||||||
|  |         messagesNotifier.clearSearch(); | ||||||
|  |       }; | ||||||
|  |     }, []); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar(title: const Text('searchMessages').tr()), | ||||||
|  |       body: Column( | ||||||
|  |         children: [ | ||||||
|  |           Column( | ||||||
|  |             children: [ | ||||||
|  |               TextField( | ||||||
|  |                 controller: searchController, | ||||||
|  |                 decoration: InputDecoration( | ||||||
|  |                   hintText: 'searchMessagesHint'.tr(), | ||||||
|  |                   border: InputBorder.none, | ||||||
|  |                   isDense: true, | ||||||
|  |                   contentPadding: EdgeInsets.only( | ||||||
|  |                     left: 16, | ||||||
|  |                     right: 16, | ||||||
|  |                     top: 12, | ||||||
|  |                     bottom: 16, | ||||||
|  |                   ), | ||||||
|  |                   suffix: IconButton( | ||||||
|  |                     iconSize: 18, | ||||||
|  |                     visualDensity: VisualDensity.compact, | ||||||
|  |                     icon: const Icon(Icons.clear), | ||||||
|  |                     onPressed: () { | ||||||
|  |                       searchController.clear(); | ||||||
|  |                       messagesNotifier.clearSearch(); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |                 onChanged: (query) { | ||||||
|  |                   messagesNotifier.searchMessages( | ||||||
|  |                     query, | ||||||
|  |                     withLinks: withLinks.value, | ||||||
|  |                     withAttachments: withAttachments.value, | ||||||
|  |                   ); | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Row( | ||||||
|  |                 children: [ | ||||||
|  |                   Expanded( | ||||||
|  |                     child: CheckboxListTile( | ||||||
|  |                       secondary: const Icon(Symbols.link), | ||||||
|  |                       title: const Text('searchLinks').tr(), | ||||||
|  |                       value: withLinks.value, | ||||||
|  |                       onChanged: (bool? value) { | ||||||
|  |                         withLinks.value = value!; | ||||||
|  |                         messagesNotifier.searchMessages( | ||||||
|  |                           searchController.text, | ||||||
|  |                           withLinks: withLinks.value, | ||||||
|  |                           withAttachments: withAttachments.value, | ||||||
|  |                         ); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                   Expanded( | ||||||
|  |                     child: CheckboxListTile( | ||||||
|  |                       secondary: const Icon(Symbols.file_copy), | ||||||
|  |                       title: const Text('searchAttachments').tr(), | ||||||
|  |                       value: withAttachments.value, | ||||||
|  |                       onChanged: (bool? value) { | ||||||
|  |                         withAttachments.value = value!; | ||||||
|  |                         messagesNotifier.searchMessages( | ||||||
|  |                           searchController.text, | ||||||
|  |                           withLinks: withLinks.value, | ||||||
|  |                           withAttachments: withAttachments.value, | ||||||
|  |                         ); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |           const Divider(height: 1), | ||||||
|  |           Expanded( | ||||||
|  |             child: messages.when( | ||||||
|  |               data: | ||||||
|  |                   (messageList) => | ||||||
|  |                       messageList.isEmpty | ||||||
|  |                           ? Center(child: Text('noMessagesFound'.tr())) | ||||||
|  |                           : SuperListView.builder( | ||||||
|  |                             padding: const EdgeInsets.symmetric(vertical: 16), | ||||||
|  |                             reverse: true, // Show newest messages at the bottom | ||||||
|  |                             itemCount: messageList.length, | ||||||
|  |                             itemBuilder: (context, index) { | ||||||
|  |                               final message = messageList[index]; | ||||||
|  |                               // Simplified MessageItem for search results, no grouping logic | ||||||
|  |                               return MessageItem( | ||||||
|  |                                 message: message, | ||||||
|  |                                 isCurrentUser: | ||||||
|  |                                     false, // Or determine based on actual user | ||||||
|  |                                 onAction: null, | ||||||
|  |                                 onJump: (_) {}, | ||||||
|  |                                 progress: null, | ||||||
|  |                                 showAvatar: true, | ||||||
|  |                               ); | ||||||
|  |                             }, | ||||||
|  |                           ), | ||||||
|  |               loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |               error: (error, _) => Center(child: Text('errorGeneric'.tr(args: [error.toString()]))), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -11,7 +11,7 @@ import 'package:island/models/publisher.dart'; | |||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/screens/creators/publishers.dart'; | import 'package:island/screens/creators/publishers.dart'; | ||||||
| import 'package:island/services/responsive.dart'; | import 'package:island/services/responsive.dart'; | ||||||
| import 'package:island/services/text.dart'; | import 'package:island/utils/text.dart'; | ||||||
| import 'package:island/widgets/account/account_picker.dart'; | import 'package:island/widgets/account/account_picker.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| @@ -212,30 +212,6 @@ class CreatorHubScreen extends HookConsumerWidget { | |||||||
|         leading: !isWide ? const PageBackButton() : null, |         leading: !isWide ? const PageBackButton() : null, | ||||||
|         title: Text('creatorHub').tr(), |         title: Text('creatorHub').tr(), | ||||||
|         actions: [ |         actions: [ | ||||||
|           IconButton( |  | ||||||
|             icon: Badge( |  | ||||||
|               label: Text( |  | ||||||
|                 publisherInvites.when( |  | ||||||
|                   data: (invites) => invites.length.toString(), |  | ||||||
|                   error: (_, _) => '0', |  | ||||||
|                   loading: () => '0', |  | ||||||
|                 ), |  | ||||||
|               ), |  | ||||||
|               isLabelVisible: publisherInvites.when( |  | ||||||
|                 data: (invites) => invites.isNotEmpty, |  | ||||||
|                 error: (_, _) => false, |  | ||||||
|                 loading: () => false, |  | ||||||
|               ), |  | ||||||
|               child: const Icon(Symbols.email), |  | ||||||
|             ), |  | ||||||
|             onPressed: () { |  | ||||||
|               showModalBottomSheet( |  | ||||||
|                 context: context, |  | ||||||
|                 isScrollControlled: true, |  | ||||||
|                 builder: (_) => const _PublisherInviteSheet(), |  | ||||||
|               ); |  | ||||||
|             }, |  | ||||||
|           ), |  | ||||||
|           DropdownButtonHideUnderline( |           DropdownButtonHideUnderline( | ||||||
|             child: DropdownButton2<SnPublisher>( |             child: DropdownButton2<SnPublisher>( | ||||||
|               alignment: Alignment.centerRight, |               alignment: Alignment.centerRight, | ||||||
| @@ -323,6 +299,23 @@ class CreatorHubScreen extends HookConsumerWidget { | |||||||
|                                 ), |                                 ), | ||||||
|                               ) ?? |                               ) ?? | ||||||
|                               []), |                               []), | ||||||
|  |                           ListTile( | ||||||
|  |                             leading: const CircleAvatar( | ||||||
|  |                               child: Icon(Symbols.mail), | ||||||
|  |                             ), | ||||||
|  |                             title: Text('publisherCollabInvitation').tr(), | ||||||
|  |                             subtitle: Text( | ||||||
|  |                               'publisherCollabInvitationCount', | ||||||
|  |                             ).plural(publisherInvites.value?.length ?? 0), | ||||||
|  |                             trailing: const Icon(Symbols.chevron_right), | ||||||
|  |                             onTap: () { | ||||||
|  |                               showModalBottomSheet( | ||||||
|  |                                 context: context, | ||||||
|  |                                 isScrollControlled: true, | ||||||
|  |                                 builder: (_) => const _PublisherInviteSheet(), | ||||||
|  |                               ); | ||||||
|  |                             }, | ||||||
|  |                           ), | ||||||
|                           ListTile( |                           ListTile( | ||||||
|                             leading: const CircleAvatar( |                             leading: const CircleAvatar( | ||||||
|                               child: Icon(Symbols.add), |                               child: Icon(Symbols.add), | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import 'package:island/widgets/poll/poll_feedback.dart'; | |||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
|  |  | ||||||
| part 'poll_list.g.dart'; | part 'poll_list.g.dart'; | ||||||
|  |  | ||||||
| @@ -86,7 +87,7 @@ class CreatorPollListScreen extends HookConsumerWidget { | |||||||
|         onPressed: () => _createPoll(context), |         onPressed: () => _createPoll(context), | ||||||
|         child: const Icon(Icons.add), |         child: const Icon(Icons.add), | ||||||
|       ), |       ), | ||||||
|       body: RefreshIndicator( |       body: ExtendedRefreshIndicator( | ||||||
|         onRefresh: () => ref.refresh(pollListNotifierProvider(pubName).future), |         onRefresh: () => ref.refresh(pollListNotifierProvider(pubName).future), | ||||||
|         child: CustomScrollView( |         child: CustomScrollView( | ||||||
|           slivers: [ |           slivers: [ | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import 'package:island/services/responsive.dart'; | |||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/content/cloud_files.dart'; | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
| import 'package:island/widgets/realms/selection_dropdown.dart'; | import 'package:island/widgets/realm/realm_selection_dropdown.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
|   | |||||||
| @@ -106,11 +106,7 @@ class StickerPacksNotifier extends _$StickerPacksNotifier | |||||||
|     try { |     try { | ||||||
|       final response = await client.get( |       final response = await client.get( | ||||||
|         '/sphere/stickers', |         '/sphere/stickers', | ||||||
|         queryParameters: { |         queryParameters: {'offset': offset, 'take': _pageSize, 'pub': pubName}, | ||||||
|           'offset': offset, |  | ||||||
|           'take': _pageSize, |  | ||||||
|           'pubName': pubName, |  | ||||||
|         }, |  | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|       final total = int.parse(response.headers.value('X-Total') ?? '0'); |       final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||||
|   | |||||||
| @@ -148,7 +148,7 @@ class _StickerPackProviderElement | |||||||
| } | } | ||||||
|  |  | ||||||
| String _$stickerPacksNotifierHash() => | String _$stickerPacksNotifierHash() => | ||||||
|     r'0a8edcf9c35396c411f1214f5e77b1e8fac6a3e6'; |     r'30024b35235f3085a5b1ec2204d0a974ee907e22'; | ||||||
|  |  | ||||||
| abstract class _$StickerPacksNotifier | abstract class _$StickerPacksNotifier | ||||||
|     extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnStickerPack>> { |     extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnStickerPack>> { | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart'; | |||||||
| import 'package:island/pods/webfeed.dart'; | import 'package:island/pods/webfeed.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; | import 'package:island/widgets/app_scaffold.dart'; | ||||||
| import 'package:island/widgets/empty_state.dart'; | import 'package:island/widgets/empty_state.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  |  | ||||||
| class WebFeedListScreen extends ConsumerWidget { | class WebFeedListScreen extends ConsumerWidget { | ||||||
| @@ -20,7 +21,10 @@ class WebFeedListScreen extends ConsumerWidget { | |||||||
|       floatingActionButton: FloatingActionButton( |       floatingActionButton: FloatingActionButton( | ||||||
|         child: const Icon(Symbols.add), |         child: const Icon(Symbols.add), | ||||||
|         onPressed: () { |         onPressed: () { | ||||||
|           context.pushNamed('creatorFeedNew', pathParameters: {'name': pubName}); |           context.pushNamed( | ||||||
|  |             'creatorFeedNew', | ||||||
|  |             pathParameters: {'name': pubName}, | ||||||
|  |           ); | ||||||
|         }, |         }, | ||||||
|       ), |       ), | ||||||
|       body: feedsAsync.when( |       body: feedsAsync.when( | ||||||
| @@ -32,7 +36,7 @@ class WebFeedListScreen extends ConsumerWidget { | |||||||
|               description: 'Add a new web feed to get started', |               description: 'Add a new web feed to get started', | ||||||
|             ); |             ); | ||||||
|           } |           } | ||||||
|           return RefreshIndicator( |           return ExtendedRefreshIndicator( | ||||||
|             onRefresh: () => ref.refresh(webFeedListProvider(pubName).future), |             onRefresh: () => ref.refresh(webFeedListProvider(pubName).future), | ||||||
|             child: ListView.builder( |             child: ListView.builder( | ||||||
|               padding: EdgeInsets.only(top: 8), |               padding: EdgeInsets.only(top: 8), | ||||||
| @@ -62,7 +66,10 @@ class WebFeedListScreen extends ConsumerWidget { | |||||||
|                     ), |                     ), | ||||||
|                     trailing: const Icon(Symbols.chevron_right), |                     trailing: const Icon(Symbols.chevron_right), | ||||||
|                     onTap: () { |                     onTap: () { | ||||||
|                       context.pushNamed('creatorFeedEdit', pathParameters: {'name': pubName, 'feedId': feed.id}); |                       context.pushNamed( | ||||||
|  |                         'creatorFeedEdit', | ||||||
|  |                         pathParameters: {'name': pubName, 'feedId': feed.id}, | ||||||
|  |                       ); | ||||||
|                     }, |                     }, | ||||||
|                   ), |                   ), | ||||||
|                 ); |                 ); | ||||||
|   | |||||||
							
								
								
									
										156
									
								
								lib/screens/developers/app_detail.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								lib/screens/developers/app_detail.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | |||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/custom_app.dart'; | ||||||
|  | import 'package:island/screens/developers/app_secrets.dart'; | ||||||
|  | import 'package:island/screens/developers/apps.dart'; | ||||||
|  | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|  | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
|  | import 'package:island/widgets/response.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
|  | class AppDetailScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String appId; | ||||||
|  |  | ||||||
|  |   const AppDetailScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     required this.appId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final tabController = useTabController(initialLength: 2); | ||||||
|  |     final appData = ref.watch( | ||||||
|  |       customAppProvider(publisherName, projectId, appId), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: Text(appData.value?.name ?? 'appDetails'.tr()), | ||||||
|  |         actions: [ | ||||||
|  |           IconButton( | ||||||
|  |             icon: const Icon(Symbols.edit), | ||||||
|  |             onPressed: | ||||||
|  |                 appData.value == null | ||||||
|  |                     ? null | ||||||
|  |                     : () { | ||||||
|  |                       context.pushNamed( | ||||||
|  |                         'developerAppEdit', | ||||||
|  |                         pathParameters: { | ||||||
|  |                           'name': publisherName, | ||||||
|  |                           'projectId': projectId, | ||||||
|  |                           'id': appId, | ||||||
|  |                         }, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |         bottom: TabBar( | ||||||
|  |           controller: tabController, | ||||||
|  |           tabs: [ | ||||||
|  |             Tab( | ||||||
|  |               child: Text( | ||||||
|  |                 'overview'.tr(), | ||||||
|  |                 textAlign: TextAlign.center, | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             Tab( | ||||||
|  |               child: Text( | ||||||
|  |                 'secrets'.tr(), | ||||||
|  |                 textAlign: TextAlign.center, | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |       body: appData.when( | ||||||
|  |         data: (app) { | ||||||
|  |           return TabBarView( | ||||||
|  |             controller: tabController, | ||||||
|  |             physics: const NeverScrollableScrollPhysics(), | ||||||
|  |             children: [ | ||||||
|  |               _AppOverview(app: app), | ||||||
|  |               AppSecretsScreen( | ||||||
|  |                 publisherName: publisherName, | ||||||
|  |                 projectId: projectId, | ||||||
|  |                 appId: appId, | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |         loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |         error: | ||||||
|  |             (err, stack) => ResponseErrorWidget( | ||||||
|  |               error: err, | ||||||
|  |               onRetry: | ||||||
|  |                   () => ref.invalidate( | ||||||
|  |                     customAppProvider(publisherName, projectId, appId), | ||||||
|  |                   ), | ||||||
|  |             ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _AppOverview extends StatelessWidget { | ||||||
|  |   final CustomApp app; | ||||||
|  |   const _AppOverview({required this.app}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return SingleChildScrollView( | ||||||
|  |       child: Column( | ||||||
|  |         children: [ | ||||||
|  |           AspectRatio( | ||||||
|  |             aspectRatio: 16 / 7, | ||||||
|  |             child: Stack( | ||||||
|  |               clipBehavior: Clip.none, | ||||||
|  |               fit: StackFit.expand, | ||||||
|  |               children: [ | ||||||
|  |                 Container( | ||||||
|  |                   color: Theme.of(context).colorScheme.surfaceContainer, | ||||||
|  |                   child: | ||||||
|  |                       app.background != null | ||||||
|  |                           ? CloudFileWidget( | ||||||
|  |                             item: app.background!, | ||||||
|  |                             fit: BoxFit.cover, | ||||||
|  |                           ) | ||||||
|  |                           : const SizedBox.shrink(), | ||||||
|  |                 ), | ||||||
|  |                 Positioned( | ||||||
|  |                   left: 20, | ||||||
|  |                   bottom: -32, | ||||||
|  |                   child: ProfilePictureWidget( | ||||||
|  |                     fileId: app.picture?.id, | ||||||
|  |                     radius: 40, | ||||||
|  |                     fallbackIcon: Symbols.apps, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ).padding(bottom: 32), | ||||||
|  |           ListTile(title: Text('name'.tr()), subtitle: Text(app.name)), | ||||||
|  |           ListTile(title: Text('slug'.tr()), subtitle: Text(app.slug)), | ||||||
|  |           if (app.description?.isNotEmpty ?? false) | ||||||
|  |             ListTile( | ||||||
|  |               title: Text('description'.tr()), | ||||||
|  |               subtitle: Text(app.description!), | ||||||
|  |             ), | ||||||
|  |         ], | ||||||
|  |       ).padding(bottom: 24), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										252
									
								
								lib/screens/developers/app_secrets.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								lib/screens/developers/app_secrets.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,252 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter/services.dart'; | ||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/custom_app_secret.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/services/time.dart'; | ||||||
|  | import 'package:island/widgets/alert.dart'; | ||||||
|  | import 'package:island/widgets/content/sheet.dart'; | ||||||
|  | import 'package:island/widgets/response.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  |  | ||||||
|  | part 'app_secrets.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<List<CustomAppSecret>> customAppSecrets( | ||||||
|  |   Ref ref, | ||||||
|  |   String publisherName, | ||||||
|  |   String projectId, | ||||||
|  |   String appId, | ||||||
|  | ) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await client.get( | ||||||
|  |     '/develop/developers/$publisherName/projects/$projectId/apps/$appId/secrets', | ||||||
|  |   ); | ||||||
|  |   return (resp.data as List) | ||||||
|  |       .map((e) => CustomAppSecret.fromJson(e)) | ||||||
|  |       .cast<CustomAppSecret>() | ||||||
|  |       .toList(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class AppSecretsScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String appId; | ||||||
|  |  | ||||||
|  |   const AppSecretsScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     required this.appId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final secrets = ref.watch( | ||||||
|  |       customAppSecretsProvider(publisherName, projectId, appId), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     void showNewSecretSheet(String newSecret) { | ||||||
|  |       showModalBottomSheet( | ||||||
|  |         context: context, | ||||||
|  |         isScrollControlled: true, | ||||||
|  |         builder: | ||||||
|  |             (context) => SheetScaffold( | ||||||
|  |               titleText: 'newSecretGenerated'.tr(), | ||||||
|  |               child: Padding( | ||||||
|  |                 padding: const EdgeInsets.all(20.0), | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                   mainAxisSize: MainAxisSize.min, | ||||||
|  |                   children: [ | ||||||
|  |                     Text('copySecretHint'.tr()), | ||||||
|  |                     const SizedBox(height: 16), | ||||||
|  |                     Container( | ||||||
|  |                       padding: const EdgeInsets.all(12), | ||||||
|  |                       decoration: BoxDecoration( | ||||||
|  |                         color: Theme.of(context).colorScheme.surfaceContainer, | ||||||
|  |                         borderRadius: BorderRadius.circular(8), | ||||||
|  |                       ), | ||||||
|  |                       child: SelectableText(newSecret), | ||||||
|  |                     ), | ||||||
|  |                     const SizedBox(height: 20), | ||||||
|  |                     FilledButton.icon( | ||||||
|  |                       onPressed: () { | ||||||
|  |                         Clipboard.setData(ClipboardData(text: newSecret)); | ||||||
|  |                       }, | ||||||
|  |                       icon: const Icon(Symbols.copy_all), | ||||||
|  |                       label: Text('copy'.tr()), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |       ).whenComplete(() { | ||||||
|  |         ref.invalidate( | ||||||
|  |           customAppSecretsProvider(publisherName, projectId, appId), | ||||||
|  |         ); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void createSecret() { | ||||||
|  |       showModalBottomSheet( | ||||||
|  |         context: context, | ||||||
|  |         isScrollControlled: true, | ||||||
|  |         builder: (context) { | ||||||
|  |           return HookBuilder( | ||||||
|  |             builder: (context) { | ||||||
|  |               final descriptionController = useTextEditingController(); | ||||||
|  |               final expiresInController = useTextEditingController(); | ||||||
|  |               final isOidc = useState(false); | ||||||
|  |  | ||||||
|  |               return SheetScaffold( | ||||||
|  |                 titleText: 'generateSecret'.tr(), | ||||||
|  |                 child: Padding( | ||||||
|  |                   padding: const EdgeInsets.all(20.0), | ||||||
|  |                   child: Column( | ||||||
|  |                     crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                     mainAxisSize: MainAxisSize.min, | ||||||
|  |                     children: [ | ||||||
|  |                       TextFormField( | ||||||
|  |                         controller: descriptionController, | ||||||
|  |                         decoration: InputDecoration( | ||||||
|  |                           labelText: 'description'.tr(), | ||||||
|  |                         ), | ||||||
|  |                         autofocus: true, | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 20), | ||||||
|  |                       TextFormField( | ||||||
|  |                         controller: expiresInController, | ||||||
|  |                         decoration: InputDecoration( | ||||||
|  |                           labelText: 'expiresIn'.tr(), | ||||||
|  |                         ), | ||||||
|  |                         keyboardType: TextInputType.number, | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 20), | ||||||
|  |                       SwitchListTile( | ||||||
|  |                         title: Text('isOidc'.tr()), | ||||||
|  |                         value: isOidc.value, | ||||||
|  |                         onChanged: (value) => isOidc.value = value, | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 20), | ||||||
|  |                       FilledButton.icon( | ||||||
|  |                         onPressed: () async { | ||||||
|  |                           final description = descriptionController.text; | ||||||
|  |                           final expiresIn = int.tryParse( | ||||||
|  |                             expiresInController.text, | ||||||
|  |                           ); | ||||||
|  |                           Navigator.pop(context); // Close the sheet | ||||||
|  |                           try { | ||||||
|  |                             final client = ref.read(apiClientProvider); | ||||||
|  |                             final resp = await client.post( | ||||||
|  |                               '/develop/developers/$publisherName/projects/$projectId/apps/$appId/secrets', | ||||||
|  |                               data: { | ||||||
|  |                                 'description': description, | ||||||
|  |                                 'expires_in': expiresIn, | ||||||
|  |                                 'is_oidc': isOidc.value, | ||||||
|  |                               }, | ||||||
|  |                             ); | ||||||
|  |                             final newSecret = CustomAppSecret.fromJson( | ||||||
|  |                               resp.data, | ||||||
|  |                             ); | ||||||
|  |                             if (newSecret.secret != null) { | ||||||
|  |                               showNewSecretSheet(newSecret.secret!); | ||||||
|  |                             } | ||||||
|  |                           } catch (e) { | ||||||
|  |                             showErrorAlert(e.toString()); | ||||||
|  |                           } | ||||||
|  |                         }, | ||||||
|  |                         icon: const Icon(Symbols.add), | ||||||
|  |                         label: Text('create'.tr()), | ||||||
|  |                       ), | ||||||
|  |                     ], | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ); | ||||||
|  |             }, | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return secrets.when( | ||||||
|  |       data: (data) { | ||||||
|  |         return RefreshIndicator( | ||||||
|  |           onRefresh: | ||||||
|  |               () => ref.refresh( | ||||||
|  |                 customAppSecretsProvider( | ||||||
|  |                   publisherName, | ||||||
|  |                   projectId, | ||||||
|  |                   appId, | ||||||
|  |                 ).future, | ||||||
|  |               ), | ||||||
|  |           child: Column( | ||||||
|  |             children: [ | ||||||
|  |               ListTile( | ||||||
|  |                 leading: const Icon(Symbols.add), | ||||||
|  |                 title: Text('generateSecret'.tr()), | ||||||
|  |                 onTap: createSecret, | ||||||
|  |               ), | ||||||
|  |               const Divider(height: 1), | ||||||
|  |               Expanded( | ||||||
|  |                 child: ListView.builder( | ||||||
|  |                   padding: EdgeInsets.zero, | ||||||
|  |                   itemCount: data.length, | ||||||
|  |                   itemBuilder: (context, index) { | ||||||
|  |                     final secret = data[index]; | ||||||
|  |                     return ListTile( | ||||||
|  |                       title: Text(secret.description ?? secret.id), | ||||||
|  |                       subtitle: Text( | ||||||
|  |                         'createdAt'.tr(args: [secret.createdAt.formatSystem()]), | ||||||
|  |                       ), | ||||||
|  |                       trailing: Row( | ||||||
|  |                         mainAxisSize: MainAxisSize.min, | ||||||
|  |                         children: [ | ||||||
|  |                           IconButton( | ||||||
|  |                             icon: const Icon(Symbols.delete, color: Colors.red), | ||||||
|  |                             onPressed: () { | ||||||
|  |                               showConfirmAlert( | ||||||
|  |                                 'deleteSecretHint'.tr(), | ||||||
|  |                                 'deleteSecret'.tr(), | ||||||
|  |                               ).then((confirm) { | ||||||
|  |                                 if (confirm) { | ||||||
|  |                                   final client = ref.read(apiClientProvider); | ||||||
|  |                                   client.delete( | ||||||
|  |                                     '/develop/developers/$publisherName/projects/$projectId/apps/$appId/secrets/${secret.id}', | ||||||
|  |                                   ); | ||||||
|  |                                   ref.invalidate( | ||||||
|  |                                     customAppSecretsProvider( | ||||||
|  |                                       publisherName, | ||||||
|  |                                       projectId, | ||||||
|  |                                       appId, | ||||||
|  |                                     ), | ||||||
|  |                                   ); | ||||||
|  |                                 } | ||||||
|  |                               }); | ||||||
|  |                             }, | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|  |       loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |       error: | ||||||
|  |           (err, stack) => ResponseErrorWidget( | ||||||
|  |             error: err, | ||||||
|  |             onRetry: | ||||||
|  |                 () => ref.invalidate( | ||||||
|  |                   customAppSecretsProvider(publisherName, projectId, appId), | ||||||
|  |                 ), | ||||||
|  |           ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										188
									
								
								lib/screens/developers/app_secrets.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								lib/screens/developers/app_secrets.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,188 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'app_secrets.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // RiverpodGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | String _$customAppSecretsHash() => r'1bc62ad812487883ce739793b22a76168d656752'; | ||||||
|  |  | ||||||
|  | /// Copied from Dart SDK | ||||||
|  | class _SystemHash { | ||||||
|  |   _SystemHash._(); | ||||||
|  |  | ||||||
|  |   static int combine(int hash, int value) { | ||||||
|  |     // ignore: parameter_assignments | ||||||
|  |     hash = 0x1fffffff & (hash + value); | ||||||
|  |     // ignore: parameter_assignments | ||||||
|  |     hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | ||||||
|  |     return hash ^ (hash >> 6); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static int finish(int hash) { | ||||||
|  |     // ignore: parameter_assignments | ||||||
|  |     hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | ||||||
|  |     // ignore: parameter_assignments | ||||||
|  |     hash = hash ^ (hash >> 11); | ||||||
|  |     return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [customAppSecrets]. | ||||||
|  | @ProviderFor(customAppSecrets) | ||||||
|  | const customAppSecretsProvider = CustomAppSecretsFamily(); | ||||||
|  |  | ||||||
|  | /// See also [customAppSecrets]. | ||||||
|  | class CustomAppSecretsFamily extends Family<AsyncValue<List<CustomAppSecret>>> { | ||||||
|  |   /// See also [customAppSecrets]. | ||||||
|  |   const CustomAppSecretsFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [customAppSecrets]. | ||||||
|  |   CustomAppSecretsProvider call( | ||||||
|  |     String publisherName, | ||||||
|  |     String projectId, | ||||||
|  |     String appId, | ||||||
|  |   ) { | ||||||
|  |     return CustomAppSecretsProvider(publisherName, projectId, appId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   CustomAppSecretsProvider getProviderOverride( | ||||||
|  |     covariant CustomAppSecretsProvider provider, | ||||||
|  |   ) { | ||||||
|  |     return call(provider.publisherName, provider.projectId, provider.appId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||||
|  |       _allTransitiveDependencies; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String? get name => r'customAppSecretsProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [customAppSecrets]. | ||||||
|  | class CustomAppSecretsProvider | ||||||
|  |     extends AutoDisposeFutureProvider<List<CustomAppSecret>> { | ||||||
|  |   /// See also [customAppSecrets]. | ||||||
|  |   CustomAppSecretsProvider(String publisherName, String projectId, String appId) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => customAppSecrets( | ||||||
|  |           ref as CustomAppSecretsRef, | ||||||
|  |           publisherName, | ||||||
|  |           projectId, | ||||||
|  |           appId, | ||||||
|  |         ), | ||||||
|  |         from: customAppSecretsProvider, | ||||||
|  |         name: r'customAppSecretsProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$customAppSecretsHash, | ||||||
|  |         dependencies: CustomAppSecretsFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: | ||||||
|  |             CustomAppSecretsFamily._allTransitiveDependencies, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         appId: appId, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   CustomAppSecretsProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     required this.appId, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String appId; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<List<CustomAppSecret>> Function(CustomAppSecretsRef provider) | ||||||
|  |     create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: CustomAppSecretsProvider._internal( | ||||||
|  |         (ref) => create(ref as CustomAppSecretsRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         appId: appId, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<List<CustomAppSecret>> createElement() { | ||||||
|  |     return _CustomAppSecretsProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is CustomAppSecretsProvider && | ||||||
|  |         other.publisherName == publisherName && | ||||||
|  |         other.projectId == projectId && | ||||||
|  |         other.appId == appId; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, publisherName.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, projectId.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, appId.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin CustomAppSecretsRef | ||||||
|  |     on AutoDisposeFutureProviderRef<List<CustomAppSecret>> { | ||||||
|  |   /// The parameter `publisherName` of this provider. | ||||||
|  |   String get publisherName; | ||||||
|  |  | ||||||
|  |   /// The parameter `projectId` of this provider. | ||||||
|  |   String get projectId; | ||||||
|  |  | ||||||
|  |   /// The parameter `appId` of this provider. | ||||||
|  |   String get appId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CustomAppSecretsProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<List<CustomAppSecret>> | ||||||
|  |     with CustomAppSecretsRef { | ||||||
|  |   _CustomAppSecretsProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get publisherName => | ||||||
|  |       (origin as CustomAppSecretsProvider).publisherName; | ||||||
|  |   @override | ||||||
|  |   String get projectId => (origin as CustomAppSecretsProvider).projectId; | ||||||
|  |   @override | ||||||
|  |   String get appId => (origin as CustomAppSecretsProvider).appId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ignore_for_file: type=lint | ||||||
|  | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
| @@ -6,7 +6,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; | |||||||
| import 'package:island/models/custom_app.dart'; | import 'package:island/models/custom_app.dart'; | ||||||
| import 'package:island/pods/network.dart'; | import 'package:island/pods/network.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| import 'package:island/widgets/app_scaffold.dart'; |  | ||||||
| import 'package:island/widgets/content/cloud_files.dart'; | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
| import 'package:island/widgets/response.dart'; | import 'package:island/widgets/response.dart'; | ||||||
| import 'package:material_symbols_icons/symbols.dart'; | import 'package:material_symbols_icons/symbols.dart'; | ||||||
| @@ -16,43 +15,79 @@ import 'package:styled_widget/styled_widget.dart'; | |||||||
| part 'apps.g.dart'; | part 'apps.g.dart'; | ||||||
|  |  | ||||||
| @riverpod | @riverpod | ||||||
| Future<List<CustomApp>> customApps(Ref ref, String publisherName) async { | Future<CustomApp> customApp( | ||||||
|  |   Ref ref, | ||||||
|  |   String publisherName, | ||||||
|  |   String projectId, | ||||||
|  |   String appId, | ||||||
|  | ) async { | ||||||
|   final client = ref.watch(apiClientProvider); |   final client = ref.watch(apiClientProvider); | ||||||
|   final resp = await client.get('/develop/developers/$publisherName/apps'); |   final resp = await client.get( | ||||||
|   return resp.data.map((e) => CustomApp.fromJson(e)).cast<CustomApp>().toList(); |     '/develop/developers/$publisherName/projects/$projectId/apps/$appId', | ||||||
|  |   ); | ||||||
|  |   return CustomApp.fromJson(resp.data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<List<CustomApp>> customApps( | ||||||
|  |   Ref ref, | ||||||
|  |   String publisherName, | ||||||
|  |   String projectId, | ||||||
|  | ) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await client.get( | ||||||
|  |     '/develop/developers/$publisherName/projects/$projectId/apps', | ||||||
|  |   ); | ||||||
|  |   return (resp.data as List) | ||||||
|  |       .map((e) => CustomApp.fromJson(e)) | ||||||
|  |       .cast<CustomApp>() | ||||||
|  |       .toList(); | ||||||
| } | } | ||||||
|  |  | ||||||
| class CustomAppsScreen extends HookConsumerWidget { | class CustomAppsScreen extends HookConsumerWidget { | ||||||
|   final String publisherName; |   final String publisherName; | ||||||
|   const CustomAppsScreen({super.key, required this.publisherName}); |   final String projectId; | ||||||
|  |   const CustomAppsScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final apps = ref.watch(customAppsProvider(publisherName)); |     final apps = ref.watch(customAppsProvider(publisherName, projectId)); | ||||||
|  |  | ||||||
|     return AppScaffold( |     return apps.when( | ||||||
|       appBar: AppBar( |       data: (data) { | ||||||
|         title: Text('customApps').tr(), |         if (data.isEmpty) { | ||||||
|         actions: [ |           return Center( | ||||||
|           IconButton( |             child: Column( | ||||||
|             icon: const Icon(Symbols.add), |               mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |               children: [ | ||||||
|  |                 Text('noCustomApps').tr(), | ||||||
|  |                 const SizedBox(height: 16), | ||||||
|  |                 ElevatedButton.icon( | ||||||
|                   onPressed: () { |                   onPressed: () { | ||||||
|                     context.pushNamed( |                     context.pushNamed( | ||||||
|                       'developerAppNew', |                       'developerAppNew', | ||||||
|                 pathParameters: {'name': publisherName}, |                       pathParameters: { | ||||||
|  |                         'name': publisherName, | ||||||
|  |                         'projectId': projectId, | ||||||
|  |                       }, | ||||||
|                     ); |                     ); | ||||||
|                   }, |                   }, | ||||||
|  |                   icon: const Icon(Symbols.add), | ||||||
|  |                   label: Text('createCustomApp').tr(), | ||||||
|                 ), |                 ), | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
|       body: apps.when( |           ); | ||||||
|         data: (data) { |  | ||||||
|           if (data.isEmpty) { |  | ||||||
|             return Center(child: Text('noCustomApps').tr()); |  | ||||||
|         } |         } | ||||||
|         return RefreshIndicator( |         return RefreshIndicator( | ||||||
|           onRefresh: |           onRefresh: | ||||||
|                 () => ref.refresh(customAppsProvider(publisherName).future), |               () => ref.refresh( | ||||||
|  |                 customAppsProvider(publisherName, projectId).future, | ||||||
|  |               ), | ||||||
|           child: ListView.builder( |           child: ListView.builder( | ||||||
|             padding: EdgeInsets.only(top: 4), |             padding: EdgeInsets.only(top: 4), | ||||||
|             itemCount: data.length, |             itemCount: data.length, | ||||||
| @@ -60,6 +95,18 @@ class CustomAppsScreen extends HookConsumerWidget { | |||||||
|               final app = data[index]; |               final app = data[index]; | ||||||
|               return Card( |               return Card( | ||||||
|                 margin: const EdgeInsets.all(8.0), |                 margin: const EdgeInsets.all(8.0), | ||||||
|  |                 clipBehavior: Clip.antiAlias, | ||||||
|  |                 child: InkWell( | ||||||
|  |                   onTap: () { | ||||||
|  |                     context.pushNamed( | ||||||
|  |                       'developerAppDetail', | ||||||
|  |                       pathParameters: { | ||||||
|  |                         'name': publisherName, | ||||||
|  |                         'projectId': projectId, | ||||||
|  |                         'appId': app.id, | ||||||
|  |                       }, | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|                   child: Column( |                   child: Column( | ||||||
|                     children: [ |                     children: [ | ||||||
|                       SizedBox( |                       SizedBox( | ||||||
| @@ -128,6 +175,7 @@ class CustomAppsScreen extends HookConsumerWidget { | |||||||
|                                 'developerAppEdit', |                                 'developerAppEdit', | ||||||
|                                 pathParameters: { |                                 pathParameters: { | ||||||
|                                   'name': publisherName, |                                   'name': publisherName, | ||||||
|  |                                   'projectId': projectId, | ||||||
|                                   'id': app.id, |                                   'id': app.id, | ||||||
|                                 }, |                                 }, | ||||||
|                               ); |                               ); | ||||||
| @@ -139,10 +187,13 @@ class CustomAppsScreen extends HookConsumerWidget { | |||||||
|                                 if (confirm) { |                                 if (confirm) { | ||||||
|                                   final client = ref.read(apiClientProvider); |                                   final client = ref.read(apiClientProvider); | ||||||
|                                   client.delete( |                                   client.delete( | ||||||
|                                     '/develop/developers/$publisherName/apps/${app.id}', |                                     '/develop/developers/$publisherName/projects/$projectId/apps/${app.id}', | ||||||
|                                   ); |                                   ); | ||||||
|                                   ref.invalidate( |                                   ref.invalidate( | ||||||
|                                     customAppsProvider(publisherName), |                                     customAppsProvider( | ||||||
|  |                                       publisherName, | ||||||
|  |                                       projectId, | ||||||
|  |                                     ), | ||||||
|                                   ); |                                   ); | ||||||
|                                 } |                                 } | ||||||
|                               }); |                               }); | ||||||
| @@ -152,6 +203,7 @@ class CustomAppsScreen extends HookConsumerWidget { | |||||||
|                       ), |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ), |                   ), | ||||||
|  |                 ), | ||||||
|               ); |               ); | ||||||
|             }, |             }, | ||||||
|           ), |           ), | ||||||
| @@ -161,7 +213,9 @@ class CustomAppsScreen extends HookConsumerWidget { | |||||||
|       error: |       error: | ||||||
|           (err, stack) => ResponseErrorWidget( |           (err, stack) => ResponseErrorWidget( | ||||||
|             error: err, |             error: err, | ||||||
|               onRetry: () => ref.invalidate(customAppsProvider(publisherName)), |             onRetry: | ||||||
|  |                 () => ref.invalidate( | ||||||
|  |                   customAppsProvider(publisherName, projectId), | ||||||
|                 ), |                 ), | ||||||
|           ), |           ), | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ part of 'apps.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$customAppsHash() => r'c6ac78060eb51a2b208a749a81ecbe0a9c608ce1'; | String _$customAppHash() => r'be05431ba8bf06fd20ee988a61c3663a68e15fc9'; | ||||||
|  |  | ||||||
| /// Copied from Dart SDK | /// Copied from Dart SDK | ||||||
| class _SystemHash { | class _SystemHash { | ||||||
| @@ -29,6 +29,148 @@ class _SystemHash { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// See also [customApp]. | ||||||
|  | @ProviderFor(customApp) | ||||||
|  | const customAppProvider = CustomAppFamily(); | ||||||
|  |  | ||||||
|  | /// See also [customApp]. | ||||||
|  | class CustomAppFamily extends Family<AsyncValue<CustomApp>> { | ||||||
|  |   /// See also [customApp]. | ||||||
|  |   const CustomAppFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [customApp]. | ||||||
|  |   CustomAppProvider call(String publisherName, String projectId, String appId) { | ||||||
|  |     return CustomAppProvider(publisherName, projectId, appId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   CustomAppProvider getProviderOverride(covariant CustomAppProvider provider) { | ||||||
|  |     return call(provider.publisherName, provider.projectId, provider.appId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get dependencies => _dependencies; | ||||||
|  |  | ||||||
|  |   static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Iterable<ProviderOrFamily>? get allTransitiveDependencies => | ||||||
|  |       _allTransitiveDependencies; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String? get name => r'customAppProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [customApp]. | ||||||
|  | class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp> { | ||||||
|  |   /// See also [customApp]. | ||||||
|  |   CustomAppProvider(String publisherName, String projectId, String appId) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => | ||||||
|  |             customApp(ref as CustomAppRef, publisherName, projectId, appId), | ||||||
|  |         from: customAppProvider, | ||||||
|  |         name: r'customAppProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$customAppHash, | ||||||
|  |         dependencies: CustomAppFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: CustomAppFamily._allTransitiveDependencies, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         appId: appId, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   CustomAppProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     required this.appId, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String appId; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<CustomApp> Function(CustomAppRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: CustomAppProvider._internal( | ||||||
|  |         (ref) => create(ref as CustomAppRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         appId: appId, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<CustomApp> createElement() { | ||||||
|  |     return _CustomAppProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is CustomAppProvider && | ||||||
|  |         other.publisherName == publisherName && | ||||||
|  |         other.projectId == projectId && | ||||||
|  |         other.appId == appId; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, publisherName.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, projectId.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, appId.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin CustomAppRef on AutoDisposeFutureProviderRef<CustomApp> { | ||||||
|  |   /// The parameter `publisherName` of this provider. | ||||||
|  |   String get publisherName; | ||||||
|  |  | ||||||
|  |   /// The parameter `projectId` of this provider. | ||||||
|  |   String get projectId; | ||||||
|  |  | ||||||
|  |   /// The parameter `appId` of this provider. | ||||||
|  |   String get appId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CustomAppProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<CustomApp> | ||||||
|  |     with CustomAppRef { | ||||||
|  |   _CustomAppProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get publisherName => (origin as CustomAppProvider).publisherName; | ||||||
|  |   @override | ||||||
|  |   String get projectId => (origin as CustomAppProvider).projectId; | ||||||
|  |   @override | ||||||
|  |   String get appId => (origin as CustomAppProvider).appId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | String _$customAppsHash() => r'450bedaf4220b8963cb44afeb14d4c0e80f01b11'; | ||||||
|  |  | ||||||
| /// See also [customApps]. | /// See also [customApps]. | ||||||
| @ProviderFor(customApps) | @ProviderFor(customApps) | ||||||
| const customAppsProvider = CustomAppsFamily(); | const customAppsProvider = CustomAppsFamily(); | ||||||
| @@ -39,15 +181,15 @@ class CustomAppsFamily extends Family<AsyncValue<List<CustomApp>>> { | |||||||
|   const CustomAppsFamily(); |   const CustomAppsFamily(); | ||||||
|  |  | ||||||
|   /// See also [customApps]. |   /// See also [customApps]. | ||||||
|   CustomAppsProvider call(String publisherName) { |   CustomAppsProvider call(String publisherName, String projectId) { | ||||||
|     return CustomAppsProvider(publisherName); |     return CustomAppsProvider(publisherName, projectId); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   CustomAppsProvider getProviderOverride( |   CustomAppsProvider getProviderOverride( | ||||||
|     covariant CustomAppsProvider provider, |     covariant CustomAppsProvider provider, | ||||||
|   ) { |   ) { | ||||||
|     return call(provider.publisherName); |     return call(provider.publisherName, provider.projectId); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static const Iterable<ProviderOrFamily>? _dependencies = null; |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
| @@ -68,9 +210,9 @@ class CustomAppsFamily extends Family<AsyncValue<List<CustomApp>>> { | |||||||
| /// See also [customApps]. | /// See also [customApps]. | ||||||
| class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | ||||||
|   /// See also [customApps]. |   /// See also [customApps]. | ||||||
|   CustomAppsProvider(String publisherName) |   CustomAppsProvider(String publisherName, String projectId) | ||||||
|     : this._internal( |     : this._internal( | ||||||
|         (ref) => customApps(ref as CustomAppsRef, publisherName), |         (ref) => customApps(ref as CustomAppsRef, publisherName, projectId), | ||||||
|         from: customAppsProvider, |         from: customAppsProvider, | ||||||
|         name: r'customAppsProvider', |         name: r'customAppsProvider', | ||||||
|         debugGetCreateSourceHash: |         debugGetCreateSourceHash: | ||||||
| @@ -80,6 +222,7 @@ class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | |||||||
|         dependencies: CustomAppsFamily._dependencies, |         dependencies: CustomAppsFamily._dependencies, | ||||||
|         allTransitiveDependencies: CustomAppsFamily._allTransitiveDependencies, |         allTransitiveDependencies: CustomAppsFamily._allTransitiveDependencies, | ||||||
|         publisherName: publisherName, |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|   CustomAppsProvider._internal( |   CustomAppsProvider._internal( | ||||||
| @@ -90,9 +233,11 @@ class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | |||||||
|     required super.debugGetCreateSourceHash, |     required super.debugGetCreateSourceHash, | ||||||
|     required super.from, |     required super.from, | ||||||
|     required this.publisherName, |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|   }) : super.internal(); |   }) : super.internal(); | ||||||
|  |  | ||||||
|   final String publisherName; |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Override overrideWith( |   Override overrideWith( | ||||||
| @@ -108,6 +253,7 @@ class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | |||||||
|         allTransitiveDependencies: null, |         allTransitiveDependencies: null, | ||||||
|         debugGetCreateSourceHash: null, |         debugGetCreateSourceHash: null, | ||||||
|         publisherName: publisherName, |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -119,13 +265,16 @@ class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   bool operator ==(Object other) { |   bool operator ==(Object other) { | ||||||
|     return other is CustomAppsProvider && other.publisherName == publisherName; |     return other is CustomAppsProvider && | ||||||
|  |         other.publisherName == publisherName && | ||||||
|  |         other.projectId == projectId; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   int get hashCode { |   int get hashCode { | ||||||
|     var hash = _SystemHash.combine(0, runtimeType.hashCode); |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|     hash = _SystemHash.combine(hash, publisherName.hashCode); |     hash = _SystemHash.combine(hash, publisherName.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, projectId.hashCode); | ||||||
|  |  | ||||||
|     return _SystemHash.finish(hash); |     return _SystemHash.finish(hash); | ||||||
|   } |   } | ||||||
| @@ -136,6 +285,9 @@ class CustomAppsProvider extends AutoDisposeFutureProvider<List<CustomApp>> { | |||||||
| mixin CustomAppsRef on AutoDisposeFutureProviderRef<List<CustomApp>> { | mixin CustomAppsRef on AutoDisposeFutureProviderRef<List<CustomApp>> { | ||||||
|   /// The parameter `publisherName` of this provider. |   /// The parameter `publisherName` of this provider. | ||||||
|   String get publisherName; |   String get publisherName; | ||||||
|  |  | ||||||
|  |   /// The parameter `projectId` of this provider. | ||||||
|  |   String get projectId; | ||||||
| } | } | ||||||
|  |  | ||||||
| class _CustomAppsProviderElement | class _CustomAppsProviderElement | ||||||
| @@ -145,6 +297,8 @@ class _CustomAppsProviderElement | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String get publisherName => (origin as CustomAppsProvider).publisherName; |   String get publisherName => (origin as CustomAppsProvider).publisherName; | ||||||
|  |   @override | ||||||
|  |   String get projectId => (origin as CustomAppsProvider).projectId; | ||||||
| } | } | ||||||
|  |  | ||||||
| // ignore_for_file: type=lint | // ignore_for_file: type=lint | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user