Compare commits
	
		
			106 Commits
		
	
	
		
			3.2.0+127
			...
			80cc8cbb40
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 80cc8cbb40 | |||
| 646e95a9fc | |||
| 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 | 
| @@ -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> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,6 +24,8 @@ android { | |||||||
|     ndkVersion = "29.0.13113456" |     ndkVersion = "29.0.13113456" | ||||||
|  |  | ||||||
|     compileOptions { |     compileOptions { | ||||||
|  |         isCoreLibraryDesugaringEnabled = true | ||||||
|  |  | ||||||
|         sourceCompatibility = JavaVersion.VERSION_17 |         sourceCompatibility = JavaVersion.VERSION_17 | ||||||
|         targetCompatibility = JavaVersion.VERSION_17 |         targetCompatibility = JavaVersion.VERSION_17 | ||||||
|     } |     } | ||||||
| @@ -63,6 +65,8 @@ android { | |||||||
| } | } | ||||||
|  |  | ||||||
| dependencies { | dependencies { | ||||||
|  |     coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") | ||||||
|  |      | ||||||
|     implementation("com.google.android.material:material:1.12.0") |     implementation("com.google.android.material:material:1.12.0") | ||||||
|     implementation("com.github.bumptech.glide:glide:4.16.0") |     implementation("com.github.bumptech.glide:glide:4.16.0") | ||||||
|     implementation("com.squareup.okhttp3:okhttp:5.1.0") |     implementation("com.squareup.okhttp3:okhttp:5.1.0") | ||||||
|   | |||||||
| @@ -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", | ||||||
| @@ -338,6 +341,7 @@ | |||||||
|   "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", | ||||||
| @@ -348,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", | ||||||
| @@ -386,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", | ||||||
| @@ -633,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", | ||||||
| @@ -643,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", | ||||||
| @@ -680,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", | ||||||
| @@ -854,5 +874,108 @@ | |||||||
|   "failedToLoadUserInfo": "Failed to load user info", |   "failedToLoadUserInfo": "Failed to load user info", | ||||||
|   "failedToLoadUserInfoNetwork": "It seems be network issue, you can tap the button below to try again.", |   "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.", |   "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" |   "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": "该日无活动。", | ||||||
| @@ -304,6 +305,7 @@ | |||||||
|   "notifications": "通知", |   "notifications": "通知", | ||||||
|   "posts": "帖子", |   "posts": "帖子", | ||||||
|   "settingsBackgroundImage": "背景图片", |   "settingsBackgroundImage": "背景图片", | ||||||
|  |   "settingsBackgroundImageEnable": "显示背景图片", | ||||||
|   "settingsBackgroundImageClear": "清除背景图片", |   "settingsBackgroundImageClear": "清除背景图片", | ||||||
|   "settingsBackgroundGenerateColor": "从背景图像生成主题色", |   "settingsBackgroundGenerateColor": "从背景图像生成主题色", | ||||||
|   "messageNone": "没有内容可显示", |   "messageNone": "没有内容可显示", | ||||||
| @@ -314,6 +316,8 @@ | |||||||
|   "chatBreakNone": "无", |   "chatBreakNone": "无", | ||||||
|   "settingsRealmCompactView": "紧凑领域视图", |   "settingsRealmCompactView": "紧凑领域视图", | ||||||
|   "settingsMixedFeed": "混合动态", |   "settingsMixedFeed": "混合动态", | ||||||
|  |   "settingsDataSavingMode": "流量节省模式", | ||||||
|  |   "dataSavingHint": "流量节省模式", | ||||||
|   "settingsAutoTranslate": "自动翻译", |   "settingsAutoTranslate": "自动翻译", | ||||||
|   "settingsHideBottomNav": "隐藏底部导航", |   "settingsHideBottomNav": "隐藏底部导航", | ||||||
|   "settingsSoundEffects": "音效", |   "settingsSoundEffects": "音效", | ||||||
| @@ -345,7 +349,7 @@ | |||||||
|   "accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。", |   "accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。", | ||||||
|   "unauthorized": "未授权", |   "unauthorized": "未授权", | ||||||
|   "unauthorizedHint": "您未登录或会话已过期,请重新登录。", |   "unauthorizedHint": "您未登录或会话已过期,请重新登录。", | ||||||
|   "publisherBelongsTo": "属于", |   "publisherBelongsTo": "属于 {}", | ||||||
|   "postContent": "内容", |   "postContent": "内容", | ||||||
|   "postSettings": "设置", |   "postSettings": "设置", | ||||||
|   "postPublisherUnselected": "未指定发布者", |   "postPublisherUnselected": "未指定发布者", | ||||||
| @@ -828,5 +832,37 @@ | |||||||
|   "failedToLoadUserInfo": "加载用户信息失败", |   "failedToLoadUserInfo": "加载用户信息失败", | ||||||
|   "failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试", |   "failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试", | ||||||
|   "failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。", |   "failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。", | ||||||
|   "okay": "了解" |   "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,7 +303,8 @@ | |||||||
|     "notifications": "通知", |     "notifications": "通知", | ||||||
|     "posts": "帖子", |     "posts": "帖子", | ||||||
|     "settingsBackgroundImage": "背景圖片", |     "settingsBackgroundImage": "背景圖片", | ||||||
|     "settingsBackgroundImageClear": "清除背景圖片", |   "settingsBackgroundImageEnable": "顯示背景圖片", | ||||||
|  |   "settingsBackgroundImageClear": "清除背景圖片", | ||||||
|     "settingsBackgroundGenerateColor": "從背景圖像生成主題色", |     "settingsBackgroundGenerateColor": "從背景圖像生成主題色", | ||||||
|     "messageNone": "沒有內容可顯示", |     "messageNone": "沒有內容可顯示", | ||||||
|     "unreadMessages": { |     "unreadMessages": { | ||||||
| @@ -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/images/media-offline.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/images/media-offline.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 461 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 307 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> | ||||||
|   | |||||||
							
								
								
									
										168
									
								
								ios/Podfile.lock
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								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 | ||||||
| @@ -248,9 +252,9 @@ PODS: | |||||||
|   - record_ios (1.1.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 | ||||||
| @@ -512,7 +524,7 @@ SPEC CHECKSUMS: | |||||||
|   receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 |   receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 | ||||||
|   record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374 |   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( | ||||||
|   | |||||||
| @@ -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) { | ||||||
| @@ -169,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); | ||||||
| @@ -186,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) { | ||||||
| @@ -246,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(); | ||||||
|           } |           } | ||||||
| @@ -262,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, | ||||||
|   | |||||||
| @@ -13,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, | ||||||
| @@ -70,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, | ||||||
| @@ -208,3 +212,37 @@ sealed class SnAuthDeviceWithChallenge with _$SnAuthDeviceWithChallenge { | |||||||
|   factory SnAuthDeviceWithChallenge.fromJson(Map<String, dynamic> json) => |   factory SnAuthDeviceWithChallenge.fromJson(Map<String, dynamic> json) => | ||||||
|       _$SnAuthDeviceWithChallengeFromJson(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); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ T _$identity<T>(T value) => value; | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnAccount { | mixin _$SnAccount { | ||||||
|  |  | ||||||
|  String get id; String get name; String get nick; String get language; bool get isSuperuser; SnAccountProfile get profile; SnWalletSubscriptionRef? get perkSubscription; List<SnAccountBadge> get badges; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; |  String get id; String get name; String get nick; String get language; String get region; bool get isSuperuser; String? get automatedId; SnAccountProfile get profile; SnWalletSubscriptionRef? get perkSubscription; List<SnAccountBadge> get badges; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
| /// Create a copy of SnAccount | /// Create a copy of SnAccount | ||||||
| /// 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 @@ $SnAccountCopyWith<SnAccount> get copyWith => _$SnAccountCopyWithImpl<SnAccount> | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.profile, profile) || other.profile == profile)&&(identical(other.perkSubscription, perkSubscription) || other.perkSubscription == perkSubscription)&&const DeepCollectionEquality().equals(other.badges, badges)&&(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 SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.region, region) || other.region == region)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.automatedId, automatedId) || other.automatedId == automatedId)&&(identical(other.profile, profile) || other.profile == profile)&&(identical(other.perkSubscription, perkSubscription) || other.perkSubscription == perkSubscription)&&const DeepCollectionEquality().equals(other.badges, badges)&&(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.hash(runtimeType,id,name,nick,language,isSuperuser,profile,perkSubscription,const DeepCollectionEquality().hash(badges),createdAt,updatedAt,deletedAt); | int get hashCode => Object.hash(runtimeType,id,name,nick,language,region,isSuperuser,automatedId,profile,perkSubscription,const DeepCollectionEquality().hash(badges),createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, isSuperuser: $isSuperuser, profile: $profile, perkSubscription: $perkSubscription, badges: $badges, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, region: $region, isSuperuser: $isSuperuser, automatedId: $automatedId, profile: $profile, perkSubscription: $perkSubscription, badges: $badges, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -48,7 +48,7 @@ abstract mixin class $SnAccountCopyWith<$Res>  { | |||||||
|   factory $SnAccountCopyWith(SnAccount value, $Res Function(SnAccount) _then) = _$SnAccountCopyWithImpl; |   factory $SnAccountCopyWith(SnAccount value, $Res Function(SnAccount) _then) = _$SnAccountCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String name, String nick, String language, bool isSuperuser, SnAccountProfile profile, SnWalletSubscriptionRef? perkSubscription, List<SnAccountBadge> badges, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, String name, String nick, String language, String region, bool isSuperuser, String? automatedId, SnAccountProfile profile, SnWalletSubscriptionRef? perkSubscription, List<SnAccountBadge> badges, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -65,14 +65,16 @@ class _$SnAccountCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccount | /// Create a copy of SnAccount | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? isSuperuser = null,Object? profile = null,Object? perkSubscription = freezed,Object? badges = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? region = null,Object? isSuperuser = null,Object? automatedId = freezed,Object? profile = null,Object? perkSubscription = freezed,Object? badges = 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,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | ||||||
| as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,region: null == region ? _self.region : region // ignore: cast_nullable_to_non_nullable | ||||||
| as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | as bool,automatedId: freezed == automatedId ? _self.automatedId : automatedId // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountProfile,perkSubscription: freezed == perkSubscription ? _self.perkSubscription : perkSubscription // ignore: cast_nullable_to_non_nullable | as SnAccountProfile,perkSubscription: freezed == perkSubscription ? _self.perkSubscription : perkSubscription // ignore: cast_nullable_to_non_nullable | ||||||
| as SnWalletSubscriptionRef?,badges: null == badges ? _self.badges : badges // ignore: cast_nullable_to_non_nullable | as SnWalletSubscriptionRef?,badges: null == badges ? _self.badges : badges // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnAccountBadge>,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | as List<SnAccountBadge>,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -181,10 +183,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String name,  String nick,  String language,  bool isSuperuser,  SnAccountProfile profile,  SnWalletSubscriptionRef? perkSubscription,  List<SnAccountBadge> badges,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String name,  String nick,  String language,  String region,  bool isSuperuser,  String? automatedId,  SnAccountProfile profile,  SnWalletSubscriptionRef? perkSubscription,  List<SnAccountBadge> badges,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccount() when $default != null: | case _SnAccount() when $default != null: | ||||||
| return $default(_that.id,_that.name,_that.nick,_that.language,_that.isSuperuser,_that.profile,_that.perkSubscription,_that.badges,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.name,_that.nick,_that.language,_that.region,_that.isSuperuser,_that.automatedId,_that.profile,_that.perkSubscription,_that.badges,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -202,10 +204,10 @@ return $default(_that.id,_that.name,_that.nick,_that.language,_that.isSuperuser, | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String name,  String nick,  String language,  bool isSuperuser,  SnAccountProfile profile,  SnWalletSubscriptionRef? perkSubscription,  List<SnAccountBadge> badges,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String name,  String nick,  String language,  String region,  bool isSuperuser,  String? automatedId,  SnAccountProfile profile,  SnWalletSubscriptionRef? perkSubscription,  List<SnAccountBadge> badges,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccount(): | case _SnAccount(): | ||||||
| return $default(_that.id,_that.name,_that.nick,_that.language,_that.isSuperuser,_that.profile,_that.perkSubscription,_that.badges,_that.createdAt,_that.updatedAt,_that.deletedAt);} | return $default(_that.id,_that.name,_that.nick,_that.language,_that.region,_that.isSuperuser,_that.automatedId,_that.profile,_that.perkSubscription,_that.badges,_that.createdAt,_that.updatedAt,_that.deletedAt);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -219,10 +221,10 @@ return $default(_that.id,_that.name,_that.nick,_that.language,_that.isSuperuser, | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String name,  String nick,  String language,  bool isSuperuser,  SnAccountProfile profile,  SnWalletSubscriptionRef? perkSubscription,  List<SnAccountBadge> badges,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String name,  String nick,  String language,  String region,  bool isSuperuser,  String? automatedId,  SnAccountProfile profile,  SnWalletSubscriptionRef? perkSubscription,  List<SnAccountBadge> badges,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccount() when $default != null: | case _SnAccount() when $default != null: | ||||||
| return $default(_that.id,_that.name,_that.nick,_that.language,_that.isSuperuser,_that.profile,_that.perkSubscription,_that.badges,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.name,_that.nick,_that.language,_that.region,_that.isSuperuser,_that.automatedId,_that.profile,_that.perkSubscription,_that.badges,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -234,14 +236,16 @@ return $default(_that.id,_that.name,_that.nick,_that.language,_that.isSuperuser, | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnAccount implements SnAccount { | class _SnAccount implements SnAccount { | ||||||
|   const _SnAccount({required this.id, required this.name, required this.nick, required this.language, required this.isSuperuser, required this.profile, required this.perkSubscription, final  List<SnAccountBadge> badges = const [], required this.createdAt, required this.updatedAt, required this.deletedAt}): _badges = badges; |   const _SnAccount({required this.id, required this.name, required this.nick, required this.language, this.region = "", required this.isSuperuser, required this.automatedId, required this.profile, required this.perkSubscription, final  List<SnAccountBadge> badges = const [], required this.createdAt, required this.updatedAt, required this.deletedAt}): _badges = badges; | ||||||
|   factory _SnAccount.fromJson(Map<String, dynamic> json) => _$SnAccountFromJson(json); |   factory _SnAccount.fromJson(Map<String, dynamic> json) => _$SnAccountFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @override final  String name; | @override final  String name; | ||||||
| @override final  String nick; | @override final  String nick; | ||||||
| @override final  String language; | @override final  String language; | ||||||
|  | @override@JsonKey() final  String region; | ||||||
| @override final  bool isSuperuser; | @override final  bool isSuperuser; | ||||||
|  | @override final  String? automatedId; | ||||||
| @override final  SnAccountProfile profile; | @override final  SnAccountProfile profile; | ||||||
| @override final  SnWalletSubscriptionRef? perkSubscription; | @override final  SnWalletSubscriptionRef? perkSubscription; | ||||||
|  final  List<SnAccountBadge> _badges; |  final  List<SnAccountBadge> _badges; | ||||||
| @@ -268,16 +272,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.profile, profile) || other.profile == profile)&&(identical(other.perkSubscription, perkSubscription) || other.perkSubscription == perkSubscription)&&const DeepCollectionEquality().equals(other._badges, _badges)&&(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 _SnAccount&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.language, language) || other.language == language)&&(identical(other.region, region) || other.region == region)&&(identical(other.isSuperuser, isSuperuser) || other.isSuperuser == isSuperuser)&&(identical(other.automatedId, automatedId) || other.automatedId == automatedId)&&(identical(other.profile, profile) || other.profile == profile)&&(identical(other.perkSubscription, perkSubscription) || other.perkSubscription == perkSubscription)&&const DeepCollectionEquality().equals(other._badges, _badges)&&(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.hash(runtimeType,id,name,nick,language,isSuperuser,profile,perkSubscription,const DeepCollectionEquality().hash(_badges),createdAt,updatedAt,deletedAt); | int get hashCode => Object.hash(runtimeType,id,name,nick,language,region,isSuperuser,automatedId,profile,perkSubscription,const DeepCollectionEquality().hash(_badges),createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, isSuperuser: $isSuperuser, profile: $profile, perkSubscription: $perkSubscription, badges: $badges, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccount(id: $id, name: $name, nick: $nick, language: $language, region: $region, isSuperuser: $isSuperuser, automatedId: $automatedId, profile: $profile, perkSubscription: $perkSubscription, badges: $badges, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -288,7 +292,7 @@ abstract mixin class _$SnAccountCopyWith<$Res> implements $SnAccountCopyWith<$Re | |||||||
|   factory _$SnAccountCopyWith(_SnAccount value, $Res Function(_SnAccount) _then) = __$SnAccountCopyWithImpl; |   factory _$SnAccountCopyWith(_SnAccount value, $Res Function(_SnAccount) _then) = __$SnAccountCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String name, String nick, String language, bool isSuperuser, SnAccountProfile profile, SnWalletSubscriptionRef? perkSubscription, List<SnAccountBadge> badges, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, String name, String nick, String language, String region, bool isSuperuser, String? automatedId, SnAccountProfile profile, SnWalletSubscriptionRef? perkSubscription, List<SnAccountBadge> badges, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -305,14 +309,16 @@ class __$SnAccountCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccount | /// Create a copy of SnAccount | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? isSuperuser = null,Object? profile = null,Object? perkSubscription = freezed,Object? badges = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? nick = null,Object? language = null,Object? region = null,Object? isSuperuser = null,Object? automatedId = freezed,Object? profile = null,Object? perkSubscription = freezed,Object? badges = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|   return _then(_SnAccount( |   return _then(_SnAccount( | ||||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
| as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable | ||||||
| as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | as String,nick: null == nick ? _self.nick : nick // ignore: cast_nullable_to_non_nullable | ||||||
| as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,region: null == region ? _self.region : region // ignore: cast_nullable_to_non_nullable | ||||||
| as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | as String,isSuperuser: null == isSuperuser ? _self.isSuperuser : isSuperuser // ignore: cast_nullable_to_non_nullable | ||||||
| as bool,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | as bool,automatedId: freezed == automatedId ? _self.automatedId : automatedId // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String?,profile: null == profile ? _self.profile : profile // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountProfile,perkSubscription: freezed == perkSubscription ? _self.perkSubscription : perkSubscription // ignore: cast_nullable_to_non_nullable | as SnAccountProfile,perkSubscription: freezed == perkSubscription ? _self.perkSubscription : perkSubscription // ignore: cast_nullable_to_non_nullable | ||||||
| as SnWalletSubscriptionRef?,badges: null == badges ? _self._badges : badges // ignore: cast_nullable_to_non_nullable | as SnWalletSubscriptionRef?,badges: null == badges ? _self._badges : badges // ignore: cast_nullable_to_non_nullable | ||||||
| as List<SnAccountBadge>,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | as List<SnAccountBadge>,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -610,7 +616,7 @@ as String, | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnAccountProfile { | mixin _$SnAccountProfile { | ||||||
|  |  | ||||||
|  String get id; String get firstName; String get middleName; String get lastName; String get bio; String get gender; String get pronouns; String get location; String get timeZone; DateTime? get birthday;@ProfileLinkConverter() List<ProfileLink> get links; DateTime? get lastSeenAt; SnAccountBadge? get activeBadge; int get experience; int get level; double get levelingProgress; SnCloudFile? get picture; SnCloudFile? get background; SnVerificationMark? get verification; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; |  String get id; String get firstName; String get middleName; String get lastName; String get bio; String get gender; String get pronouns; String get location; String get timeZone; DateTime? get birthday;@ProfileLinkConverter() List<ProfileLink> get links; DateTime? get lastSeenAt; SnAccountBadge? get activeBadge; int get experience; int get level; double get socialCredits; int get socialCreditsLevel; double get levelingProgress; SnCloudFile? get picture; SnCloudFile? get background; SnVerificationMark? get verification; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
| /// Create a copy of SnAccountProfile | /// Create a copy of SnAccountProfile | ||||||
| /// 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) | ||||||
| @@ -623,16 +629,16 @@ $SnAccountProfileCopyWith<SnAccountProfile> get copyWith => _$SnAccountProfileCo | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other.links, links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(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 SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other.links, links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.socialCreditsLevel, socialCreditsLevel) || other.socialCreditsLevel == socialCreditsLevel)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(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,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(links),lastSeenAt,activeBadge,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(links),lastSeenAt,activeBadge,experience,level,socialCredits,socialCreditsLevel,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, socialCredits: $socialCredits, socialCreditsLevel: $socialCreditsLevel, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -643,7 +649,7 @@ abstract mixin class $SnAccountProfileCopyWith<$Res>  { | |||||||
|   factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl; |   factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -660,7 +666,7 @@ class _$SnAccountProfileCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccountProfile | /// Create a copy of SnAccountProfile | ||||||
| /// 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? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? socialCredits = null,Object? socialCreditsLevel = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,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,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -677,6 +683,8 @@ as List<ProfileLink>,lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : last | |||||||
| as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | ||||||
| as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,socialCreditsLevel: null == socialCreditsLevel ? _self.socialCreditsLevel : socialCreditsLevel // ignore: cast_nullable_to_non_nullable | ||||||
| as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | ||||||
| as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -814,10 +822,10 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double socialCredits,  int socialCreditsLevel,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccountProfile() when $default != null: | case _SnAccountProfile() when $default != null: | ||||||
| return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return orElse(); |   return orElse(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -835,10 +843,10 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double socialCredits,  int socialCreditsLevel,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccountProfile(): | case _SnAccountProfile(): | ||||||
| return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);} | return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);} | ||||||
| } | } | ||||||
| /// A variant of `when` that fallback to returning `null` | /// A variant of `when` that fallback to returning `null` | ||||||
| /// | /// | ||||||
| @@ -852,10 +860,10 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  String firstName,  String middleName,  String lastName,  String bio,  String gender,  String pronouns,  String location,  String timeZone,  DateTime? birthday, @ProfileLinkConverter()  List<ProfileLink> links,  DateTime? lastSeenAt,  SnAccountBadge? activeBadge,  int experience,  int level,  double socialCredits,  int socialCreditsLevel,  double levelingProgress,  SnCloudFile? picture,  SnCloudFile? background,  SnVerificationMark? verification,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | ||||||
| switch (_that) { | switch (_that) { | ||||||
| case _SnAccountProfile() when $default != null: | case _SnAccountProfile() when $default != null: | ||||||
| return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|   return null; |   return null; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -867,7 +875,7 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b | |||||||
| @JsonSerializable() | @JsonSerializable() | ||||||
|  |  | ||||||
| class _SnAccountProfile implements SnAccountProfile { | class _SnAccountProfile implements SnAccountProfile { | ||||||
|   const _SnAccountProfile({required this.id, this.firstName = '', this.middleName = '', this.lastName = '', this.bio = '', this.gender = '', this.pronouns = '', this.location = '', this.timeZone = '', this.birthday, @ProfileLinkConverter() final  List<ProfileLink> links = const [], this.lastSeenAt, this.activeBadge, required this.experience, required this.level, required this.levelingProgress, required this.picture, required this.background, required this.verification, required this.createdAt, required this.updatedAt, required this.deletedAt}): _links = links; |   const _SnAccountProfile({required this.id, this.firstName = '', this.middleName = '', this.lastName = '', this.bio = '', this.gender = '', this.pronouns = '', this.location = '', this.timeZone = '', this.birthday, @ProfileLinkConverter() final  List<ProfileLink> links = const [], this.lastSeenAt, this.activeBadge, required this.experience, required this.level, this.socialCredits = 100, this.socialCreditsLevel = 0, required this.levelingProgress, required this.picture, required this.background, required this.verification, required this.createdAt, required this.updatedAt, required this.deletedAt}): _links = links; | ||||||
|   factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json); |   factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json); | ||||||
|  |  | ||||||
| @override final  String id; | @override final  String id; | ||||||
| @@ -891,6 +899,8 @@ class _SnAccountProfile implements SnAccountProfile { | |||||||
| @override final  SnAccountBadge? activeBadge; | @override final  SnAccountBadge? activeBadge; | ||||||
| @override final  int experience; | @override final  int experience; | ||||||
| @override final  int level; | @override final  int level; | ||||||
|  | @override@JsonKey() final  double socialCredits; | ||||||
|  | @override@JsonKey() final  int socialCreditsLevel; | ||||||
| @override final  double levelingProgress; | @override final  double levelingProgress; | ||||||
| @override final  SnCloudFile? picture; | @override final  SnCloudFile? picture; | ||||||
| @override final  SnCloudFile? background; | @override final  SnCloudFile? background; | ||||||
| @@ -912,16 +922,16 @@ Map<String, dynamic> toJson() { | |||||||
|  |  | ||||||
| @override | @override | ||||||
| bool operator ==(Object other) { | bool operator ==(Object other) { | ||||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other._links, _links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(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 _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other._links, _links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.socialCreditsLevel, socialCreditsLevel) || other.socialCreditsLevel == socialCreditsLevel)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(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,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(_links),lastSeenAt,activeBadge,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(_links),lastSeenAt,activeBadge,experience,level,socialCredits,socialCreditsLevel,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]); | ||||||
|  |  | ||||||
| @override | @override | ||||||
| String toString() { | String toString() { | ||||||
|   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; |   return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, socialCredits: $socialCredits, socialCreditsLevel: $socialCreditsLevel, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -932,7 +942,7 @@ abstract mixin class _$SnAccountProfileCopyWith<$Res> implements $SnAccountProfi | |||||||
|   factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl; |   factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt |  String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -949,7 +959,7 @@ class __$SnAccountProfileCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnAccountProfile | /// Create a copy of SnAccountProfile | ||||||
| /// 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? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? socialCredits = null,Object? socialCreditsLevel = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|   return _then(_SnAccountProfile( |   return _then(_SnAccountProfile( | ||||||
| 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,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -966,6 +976,8 @@ as List<ProfileLink>,lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : last | |||||||
| as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable | ||||||
| as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable | ||||||
| as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,socialCreditsLevel: null == socialCreditsLevel ? _self.socialCreditsLevel : socialCreditsLevel // ignore: cast_nullable_to_non_nullable | ||||||
| as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable | ||||||
| as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable | ||||||
| as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable | ||||||
| @@ -3018,6 +3030,562 @@ as bool, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | mixin _$SnExperienceRecord { | ||||||
|  |  | ||||||
|  |  String get id; int get delta; String get reasonType; String get reason; double? get bonusMultiplier; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
|  | /// Create a copy of SnExperienceRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnExperienceRecordCopyWith<SnExperienceRecord> get copyWith => _$SnExperienceRecordCopyWithImpl<SnExperienceRecord>(this as SnExperienceRecord, _$identity); | ||||||
|  |  | ||||||
|  |   /// Serializes this SnExperienceRecord to a JSON map. | ||||||
|  |   Map<String, dynamic> toJson(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnExperienceRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.bonusMultiplier, bonusMultiplier) || other.bonusMultiplier == bonusMultiplier)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,bonusMultiplier,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnExperienceRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, bonusMultiplier: $bonusMultiplier, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class $SnExperienceRecordCopyWith<$Res>  { | ||||||
|  |   factory $SnExperienceRecordCopyWith(SnExperienceRecord value, $Res Function(SnExperienceRecord) _then) = _$SnExperienceRecordCopyWithImpl; | ||||||
|  | @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, int delta, String reasonType, String reason, double? bonusMultiplier, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class _$SnExperienceRecordCopyWithImpl<$Res> | ||||||
|  |     implements $SnExperienceRecordCopyWith<$Res> { | ||||||
|  |   _$SnExperienceRecordCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final SnExperienceRecord _self; | ||||||
|  |   final $Res Function(SnExperienceRecord) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnExperienceRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? bonusMultiplier = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|  |   return _then(_self.copyWith( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,bonusMultiplier: freezed == bonusMultiplier ? _self.bonusMultiplier : bonusMultiplier // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Adds pattern-matching-related methods to [SnExperienceRecord]. | ||||||
|  | extension SnExperienceRecordPatterns on SnExperienceRecord { | ||||||
|  | /// 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( _SnExperienceRecord value)?  $default,{required TResult orElse(),}){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnExperienceRecord() 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( _SnExperienceRecord value)  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnExperienceRecord(): | ||||||
|  | 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( _SnExperienceRecord value)?  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnExperienceRecord() 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,  int delta,  String reasonType,  String reason,  double? bonusMultiplier,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnExperienceRecord() when $default != null: | ||||||
|  | return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.bonusMultiplier,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|  |   return orElse(); | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  | /// A `switch`-like method, using callbacks. | ||||||
|  | /// | ||||||
|  | /// As opposed to `map`, this offers destructuring. | ||||||
|  | /// It is equivalent to doing: | ||||||
|  | /// ```dart | ||||||
|  | /// switch (sealedClass) { | ||||||
|  | ///   case Subclass(:final field): | ||||||
|  | ///     return ...; | ||||||
|  | ///   case Subclass2(:final field2): | ||||||
|  | ///     return ...; | ||||||
|  | /// } | ||||||
|  | /// ``` | ||||||
|  |  | ||||||
|  | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  int delta,  String reasonType,  String reason,  double? bonusMultiplier,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnExperienceRecord(): | ||||||
|  | return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.bonusMultiplier,_that.createdAt,_that.updatedAt,_that.deletedAt);} | ||||||
|  | } | ||||||
|  | /// A variant of `when` that fallback to returning `null` | ||||||
|  | /// | ||||||
|  | /// It is equivalent to doing: | ||||||
|  | /// ```dart | ||||||
|  | /// switch (sealedClass) { | ||||||
|  | ///   case Subclass(:final field): | ||||||
|  | ///     return ...; | ||||||
|  | ///   case _: | ||||||
|  | ///     return null; | ||||||
|  | /// } | ||||||
|  | /// ``` | ||||||
|  |  | ||||||
|  | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  int delta,  String reasonType,  String reason,  double? bonusMultiplier,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnExperienceRecord() when $default != null: | ||||||
|  | return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.bonusMultiplier,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|  |   return null; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | @JsonSerializable() | ||||||
|  |  | ||||||
|  | class _SnExperienceRecord implements SnExperienceRecord { | ||||||
|  |   const _SnExperienceRecord({required this.id, required this.delta, required this.reasonType, required this.reason, this.bonusMultiplier = 1.0, required this.createdAt, required this.updatedAt, required this.deletedAt}); | ||||||
|  |   factory _SnExperienceRecord.fromJson(Map<String, dynamic> json) => _$SnExperienceRecordFromJson(json); | ||||||
|  |  | ||||||
|  | @override final  String id; | ||||||
|  | @override final  int delta; | ||||||
|  | @override final  String reasonType; | ||||||
|  | @override final  String reason; | ||||||
|  | @override@JsonKey() final  double? bonusMultiplier; | ||||||
|  | @override final  DateTime createdAt; | ||||||
|  | @override final  DateTime updatedAt; | ||||||
|  | @override final  DateTime? deletedAt; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnExperienceRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | _$SnExperienceRecordCopyWith<_SnExperienceRecord> get copyWith => __$SnExperienceRecordCopyWithImpl<_SnExperienceRecord>(this, _$identity); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | Map<String, dynamic> toJson() { | ||||||
|  |   return _$SnExperienceRecordToJson(this, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnExperienceRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.bonusMultiplier, bonusMultiplier) || other.bonusMultiplier == bonusMultiplier)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,bonusMultiplier,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnExperienceRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, bonusMultiplier: $bonusMultiplier, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class _$SnExperienceRecordCopyWith<$Res> implements $SnExperienceRecordCopyWith<$Res> { | ||||||
|  |   factory _$SnExperienceRecordCopyWith(_SnExperienceRecord value, $Res Function(_SnExperienceRecord) _then) = __$SnExperienceRecordCopyWithImpl; | ||||||
|  | @override @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, int delta, String reasonType, String reason, double? bonusMultiplier, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class __$SnExperienceRecordCopyWithImpl<$Res> | ||||||
|  |     implements _$SnExperienceRecordCopyWith<$Res> { | ||||||
|  |   __$SnExperienceRecordCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final _SnExperienceRecord _self; | ||||||
|  |   final $Res Function(_SnExperienceRecord) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnExperienceRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? bonusMultiplier = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|  |   return _then(_SnExperienceRecord( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable | ||||||
|  | as int,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,bonusMultiplier: freezed == bonusMultiplier ? _self.bonusMultiplier : bonusMultiplier // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | mixin _$SnSocialCreditRecord { | ||||||
|  |  | ||||||
|  |  String get id; double get delta; String get reasonType; String get reason; DateTime? get expiredAt; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; | ||||||
|  | /// Create a copy of SnSocialCreditRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | $SnSocialCreditRecordCopyWith<SnSocialCreditRecord> get copyWith => _$SnSocialCreditRecordCopyWithImpl<SnSocialCreditRecord>(this as SnSocialCreditRecord, _$identity); | ||||||
|  |  | ||||||
|  |   /// Serializes this SnSocialCreditRecord to a JSON map. | ||||||
|  |   Map<String, dynamic> toJson(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnSocialCreditRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,expiredAt,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnSocialCreditRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class $SnSocialCreditRecordCopyWith<$Res>  { | ||||||
|  |   factory $SnSocialCreditRecordCopyWith(SnSocialCreditRecord value, $Res Function(SnSocialCreditRecord) _then) = _$SnSocialCreditRecordCopyWithImpl; | ||||||
|  | @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, double delta, String reasonType, String reason, DateTime? expiredAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class _$SnSocialCreditRecordCopyWithImpl<$Res> | ||||||
|  |     implements $SnSocialCreditRecordCopyWith<$Res> { | ||||||
|  |   _$SnSocialCreditRecordCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final SnSocialCreditRecord _self; | ||||||
|  |   final $Res Function(SnSocialCreditRecord) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnSocialCreditRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|  |   return _then(_self.copyWith( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Adds pattern-matching-related methods to [SnSocialCreditRecord]. | ||||||
|  | extension SnSocialCreditRecordPatterns on SnSocialCreditRecord { | ||||||
|  | /// 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( _SnSocialCreditRecord value)?  $default,{required TResult orElse(),}){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnSocialCreditRecord() 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( _SnSocialCreditRecord value)  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnSocialCreditRecord(): | ||||||
|  | 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( _SnSocialCreditRecord value)?  $default,){ | ||||||
|  | final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnSocialCreditRecord() 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,  double delta,  String reasonType,  String reason,  DateTime? expiredAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnSocialCreditRecord() when $default != null: | ||||||
|  | return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|  |   return orElse(); | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  | /// A `switch`-like method, using callbacks. | ||||||
|  | /// | ||||||
|  | /// As opposed to `map`, this offers destructuring. | ||||||
|  | /// It is equivalent to doing: | ||||||
|  | /// ```dart | ||||||
|  | /// switch (sealedClass) { | ||||||
|  | ///   case Subclass(:final field): | ||||||
|  | ///     return ...; | ||||||
|  | ///   case Subclass2(:final field2): | ||||||
|  | ///     return ...; | ||||||
|  | /// } | ||||||
|  | /// ``` | ||||||
|  |  | ||||||
|  | @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id,  double delta,  String reasonType,  String reason,  DateTime? expiredAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnSocialCreditRecord(): | ||||||
|  | return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);} | ||||||
|  | } | ||||||
|  | /// A variant of `when` that fallback to returning `null` | ||||||
|  | /// | ||||||
|  | /// It is equivalent to doing: | ||||||
|  | /// ```dart | ||||||
|  | /// switch (sealedClass) { | ||||||
|  | ///   case Subclass(:final field): | ||||||
|  | ///     return ...; | ||||||
|  | ///   case _: | ||||||
|  | ///     return null; | ||||||
|  | /// } | ||||||
|  | /// ``` | ||||||
|  |  | ||||||
|  | @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id,  double delta,  String reasonType,  String reason,  DateTime? expiredAt,  DateTime createdAt,  DateTime updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | ||||||
|  | switch (_that) { | ||||||
|  | case _SnSocialCreditRecord() when $default != null: | ||||||
|  | return $default(_that.id,_that.delta,_that.reasonType,_that.reason,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||||
|  |   return null; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | @JsonSerializable() | ||||||
|  |  | ||||||
|  | class _SnSocialCreditRecord implements SnSocialCreditRecord { | ||||||
|  |   const _SnSocialCreditRecord({required this.id, required this.delta, required this.reasonType, required this.reason, required this.expiredAt, required this.createdAt, required this.updatedAt, required this.deletedAt}); | ||||||
|  |   factory _SnSocialCreditRecord.fromJson(Map<String, dynamic> json) => _$SnSocialCreditRecordFromJson(json); | ||||||
|  |  | ||||||
|  | @override final  String id; | ||||||
|  | @override final  double delta; | ||||||
|  | @override final  String reasonType; | ||||||
|  | @override final  String reason; | ||||||
|  | @override final  DateTime? expiredAt; | ||||||
|  | @override final  DateTime createdAt; | ||||||
|  | @override final  DateTime updatedAt; | ||||||
|  | @override final  DateTime? deletedAt; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnSocialCreditRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @pragma('vm:prefer-inline') | ||||||
|  | _$SnSocialCreditRecordCopyWith<_SnSocialCreditRecord> get copyWith => __$SnSocialCreditRecordCopyWithImpl<_SnSocialCreditRecord>(this, _$identity); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | Map<String, dynamic> toJson() { | ||||||
|  |   return _$SnSocialCreditRecordToJson(this, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | bool operator ==(Object other) { | ||||||
|  |   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnSocialCreditRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.delta, delta) || other.delta == delta)&&(identical(other.reasonType, reasonType) || other.reasonType == reasonType)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @JsonKey(includeFromJson: false, includeToJson: false) | ||||||
|  | @override | ||||||
|  | int get hashCode => Object.hash(runtimeType,id,delta,reasonType,reason,expiredAt,createdAt,updatedAt,deletedAt); | ||||||
|  |  | ||||||
|  | @override | ||||||
|  | String toString() { | ||||||
|  |   return 'SnSocialCreditRecord(id: $id, delta: $delta, reasonType: $reasonType, reason: $reason, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// @nodoc | ||||||
|  | abstract mixin class _$SnSocialCreditRecordCopyWith<$Res> implements $SnSocialCreditRecordCopyWith<$Res> { | ||||||
|  |   factory _$SnSocialCreditRecordCopyWith(_SnSocialCreditRecord value, $Res Function(_SnSocialCreditRecord) _then) = __$SnSocialCreditRecordCopyWithImpl; | ||||||
|  | @override @useResult | ||||||
|  | $Res call({ | ||||||
|  |  String id, double delta, String reasonType, String reason, DateTime? expiredAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt | ||||||
|  | }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  | /// @nodoc | ||||||
|  | class __$SnSocialCreditRecordCopyWithImpl<$Res> | ||||||
|  |     implements _$SnSocialCreditRecordCopyWith<$Res> { | ||||||
|  |   __$SnSocialCreditRecordCopyWithImpl(this._self, this._then); | ||||||
|  |  | ||||||
|  |   final _SnSocialCreditRecord _self; | ||||||
|  |   final $Res Function(_SnSocialCreditRecord) _then; | ||||||
|  |  | ||||||
|  | /// Create a copy of SnSocialCreditRecord | ||||||
|  | /// with the given fields replaced by the non-null parameter values. | ||||||
|  | @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? delta = null,Object? reasonType = null,Object? reason = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { | ||||||
|  |   return _then(_SnSocialCreditRecord( | ||||||
|  | id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,delta: null == delta ? _self.delta : delta // ignore: cast_nullable_to_non_nullable | ||||||
|  | as double,reasonType: null == reasonType ? _self.reasonType : reasonType // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable | ||||||
|  | as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||||
|  | as DateTime?, | ||||||
|  |   )); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // dart format on | // dart format on | ||||||
|   | |||||||
| @@ -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(), | ||||||
| @@ -348,3 +356,62 @@ Map<String, dynamic> _$SnAuthDeviceWithChallengeeToJson( | |||||||
|   'challenges': instance.challenges.map((e) => e.toJson()).toList(), |   'challenges': instance.challenges.map((e) => e.toJson()).toList(), | ||||||
|   'is_current': instance.isCurrent, |   '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(), | ||||||
|  | }; | ||||||
|   | |||||||
| @@ -4,6 +4,20 @@ 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({ | ||||||
| @@ -26,7 +40,7 @@ sealed class SnAuthChallenge with _$SnAuthChallenge { | |||||||
|     required String ipAddress, |     required String ipAddress, | ||||||
|     required String userAgent, |     required String userAgent, | ||||||
|     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, | ||||||
|   | |||||||
| @@ -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 type; List<String> get blacklistFactors; List<dynamic> get audiences; List<dynamic> get scopes; String get ipAddress; String get userAgent; 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) | ||||||
| @@ -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 type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, 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 | ||||||
| @@ -337,14 +606,26 @@ as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // i | |||||||
| 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,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)); | ||||||
|  |   }); | ||||||
|  | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -423,7 +704,7 @@ return $default(_that);case _: | |||||||
| /// } | /// } | ||||||
| /// ``` | /// ``` | ||||||
|  |  | ||||||
| @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,  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.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 $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 _: | ||||||
| @@ -444,7 +725,7 @@ 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 type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  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.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_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);} | ||||||
| @@ -461,7 +742,7 @@ 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 type,  List<String> blacklistFactors,  List<dynamic> audiences,  List<dynamic> scopes,  String ipAddress,  String userAgent,  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.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 $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 _: | ||||||
| @@ -509,7 +790,7 @@ class _SnAuthChallenge implements SnAuthChallenge { | |||||||
| @override final  String ipAddress; | @override final  String ipAddress; | ||||||
| @override final  String userAgent; | @override final  String userAgent; | ||||||
| @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; | ||||||
| @@ -548,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 type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, 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 | ||||||
| @@ -580,7 +861,7 @@ as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // i | |||||||
| 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,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 | ||||||
| @@ -588,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)); | ||||||
|  |   }); | ||||||
|  | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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, | ||||||
| @@ -30,7 +48,12 @@ _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) => | |||||||
|       ipAddress: json['ip_address'] as String, |       ipAddress: json['ip_address'] as String, | ||||||
|       userAgent: json['user_agent'] as String, |       userAgent: json['user_agent'] 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), | ||||||
| @@ -54,7 +77,7 @@ Map<String, dynamic> _$SnAuthChallengeToJson(_SnAuthChallenge instance) => | |||||||
|       'ip_address': instance.ipAddress, |       'ip_address': instance.ipAddress, | ||||||
|       'user_agent': instance.userAgent, |       'user_agent': instance.userAgent, | ||||||
|       '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(), | ||||||
|   | |||||||
							
								
								
									
										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, | ||||||
|  |     }; | ||||||
| @@ -104,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) => | ||||||
|   | |||||||
| @@ -1410,7 +1410,7 @@ $SnAccountStatusCopyWith<$Res>? get status { | |||||||
| /// @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) | ||||||
| @@ -1443,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 | ||||||
| @@ -1460,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 $SnChatMessageCopyWith<$Res>(_self.lastMessage, (value) { |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnChatMessageCopyWith<$Res>(_self.lastMessage!, (value) { | ||||||
|     return _then(_self.copyWith(lastMessage: value)); |     return _then(_self.copyWith(lastMessage: value)); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| @@ -1555,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 _: | ||||||
| @@ -1576,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);} | ||||||
| @@ -1593,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 _: | ||||||
| @@ -1612,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. | ||||||
| @@ -1647,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 | ||||||
| @@ -1664,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?, | ||||||
|   )); |   )); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1676,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 $SnChatMessageCopyWith<$Res>(_self.lastMessage, (value) { |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return $SnChatMessageCopyWith<$Res>(_self.lastMessage!, (value) { | ||||||
|     return _then(_self.copyWith(lastMessage: value)); |     return _then(_self.copyWith(lastMessage: value)); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -213,15 +213,18 @@ Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) => | |||||||
| _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'] as Map<String, dynamic>, |           json['last_message'] == null | ||||||
|       ), |               ? null | ||||||
|  |               : SnChatMessage.fromJson( | ||||||
|  |                 json['last_message'] as Map<String, dynamic>, | ||||||
|  |               ), | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
| 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) => | ||||||
|   | |||||||
							
								
								
									
										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'], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -27,6 +27,7 @@ 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, | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ T _$identity<T>(T value) => value; | |||||||
| /// @nodoc | /// @nodoc | ||||||
| mixin _$SnPost { | mixin _$SnPost { | ||||||
|  |  | ||||||
|  String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; 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; 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; |  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.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.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)); |   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,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,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]); | 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, slug: $slug, 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, 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)'; |   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,7 +48,7 @@ abstract mixin class $SnPostCopyWith<$Res>  { | |||||||
|   factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl; |   factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl; | ||||||
| @useResult | @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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 |  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 | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res> | |||||||
|  |  | ||||||
| /// Create a copy of SnPost | /// Create a copy of SnPost | ||||||
| /// with the given fields replaced by the non-null parameter values. | /// with the given fields replaced by the non-null parameter values. | ||||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? 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? 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,}) { | @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 | ||||||
| @@ -83,7 +83,8 @@ 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 | ||||||
| @@ -242,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,  String? slug,  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,  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; | @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.slug,_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.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 $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(); | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -263,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,  String? slug,  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,  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; | @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.slug,_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.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);} | 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` | ||||||
| /// | /// | ||||||
| @@ -280,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,  String? slug,  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,  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; | @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.slug,_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.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 $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; | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -295,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.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.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; |   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; | ||||||
| @@ -322,6 +323,7 @@ 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; | ||||||
| @@ -398,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.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.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)); |   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,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,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]); | 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, slug: $slug, 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, 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)'; |   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)'; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -418,7 +420,7 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> { | |||||||
|   factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl; |   factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl; | ||||||
| @override @useResult | @override @useResult | ||||||
| $Res call({ | $Res call({ | ||||||
|  String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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 |  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 | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -435,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? slug = 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? 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,}) { | @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 | ||||||
| @@ -453,7 +455,8 @@ 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 | ||||||
|   | |||||||
| @@ -29,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 | ||||||
| @@ -109,6 +110,7 @@ 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, | ||||||
|   | |||||||
| @@ -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, | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -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') ? null : _$callNotifierHash, | ||||||
|           const bool.fromEnvironment('dart.vm.product') |   dependencies: null, | ||||||
|               ? null |   allTransitiveDependencies: null, | ||||||
|               : _$callNotifierHash, | ); | ||||||
|       dependencies: 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,10 +15,12 @@ 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'; | ||||||
| @@ -54,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 | ||||||
| @@ -71,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), | ||||||
| @@ -104,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); | ||||||
| @@ -129,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'); |  | ||||||
|     return null; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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,5 +1,6 @@ | |||||||
| import 'dart:convert'; | import 'dart:convert'; | ||||||
| import 'dart:developer'; | import 'dart:developer'; | ||||||
|  | import 'dart:io' show Platform; | ||||||
|  |  | ||||||
| import 'package:dio/dio.dart'; | import 'package:dio/dio.dart'; | ||||||
| import 'package:easy_localization/easy_localization.dart'; | import 'package:easy_localization/easy_localization.dart'; | ||||||
| @@ -28,7 +29,10 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> { | |||||||
|       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); | ||||||
|       FirebaseAnalytics.instance.setUserId(id: user.id); |  | ||||||
|  |       if (kIsWeb || !Platform.isLinux) { | ||||||
|  |         FirebaseAnalytics.instance.setUserId(id: user.id); | ||||||
|  |       } | ||||||
|     } catch (error, stackTrace) { |     } catch (error, stackTrace) { | ||||||
|       if (!kIsWeb) { |       if (!kIsWeb) { | ||||||
|         if (error is DioException) { |         if (error is DioException) { | ||||||
| @@ -83,7 +87,9 @@ 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); | ||||||
|     FirebaseAnalytics.instance.setUserId(id: null); |     if (kIsWeb || !Platform.isLinux) { | ||||||
|  |       FirebaseAnalytics.instance.setUserId(id: null); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										160
									
								
								lib/route.dart
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								lib/route.dart
									
									
									
									
									
								
							| @@ -6,11 +6,20 @@ 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'; | ||||||
| @@ -29,12 +38,15 @@ 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'; | ||||||
| @@ -52,6 +64,7 @@ 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>(); | ||||||
| @@ -286,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( |               GoRoute( | ||||||
|                 name: 'developerAppNew', |                 name: 'developerProjectNew', | ||||||
|                 path: '/developers/:name/apps/new', |                 path: '/developers/:name/projects/new', | ||||||
|                 builder: |                 builder: | ||||||
|                     (context, state) => NewCustomAppScreen( |                     (context, state) => NewProjectScreen( | ||||||
|                       publisherName: state.pathParameters['name']!, |                       publisherName: state.pathParameters['name']!, | ||||||
|                     ), |                     ), | ||||||
|               ), |               ), | ||||||
|               GoRoute( |               GoRoute( | ||||||
|                 name: 'developerAppEdit', |                 name: 'developerProjectEdit', | ||||||
|                 path: '/developers/:name/apps/:id', |                 path: '/developers/:name/projects/:id/edit', | ||||||
|                 builder: |                 builder: | ||||||
|                     (context, state) => EditAppScreen( |                     (context, state) => EditProjectScreen( | ||||||
|                       publisherName: state.pathParameters['name']!, |                       publisherName: state.pathParameters['name']!, | ||||||
|                       id: state.pathParameters['id']!, |                       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( | ||||||
|  |                     name: 'developerAppNew', | ||||||
|  |                     path: 'apps/new', | ||||||
|  |                     builder: | ||||||
|  |                         (context, state) => NewCustomAppScreen( | ||||||
|  |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|  |                         ), | ||||||
|  |                   ), | ||||||
|  |                   GoRoute( | ||||||
|  |                     name: 'developerAppEdit', | ||||||
|  |                     path: 'apps/:id/edit', | ||||||
|  |                     builder: | ||||||
|  |                         (context, state) => EditAppScreen( | ||||||
|  |                           publisherName: state.pathParameters['name']!, | ||||||
|  |                           projectId: state.pathParameters['projectId']!, | ||||||
|  |                           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']!, | ||||||
|  |                         ), | ||||||
|  |                   ), | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|  |  | ||||||
| @@ -376,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', | ||||||
| @@ -391,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', | ||||||
| @@ -402,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', | ||||||
| @@ -459,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); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|  |  | ||||||
| @@ -528,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', | ||||||
| @@ -538,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', | ||||||
|   | |||||||
| @@ -68,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( | ||||||
| @@ -112,20 +113,22 @@ class AccountScreen extends HookConsumerWidget { | |||||||
|                               crossAxisAlignment: CrossAxisAlignment.baseline, |                               crossAxisAlignment: CrossAxisAlignment.baseline, | ||||||
|                               textBaseline: TextBaseline.alphabetic, |                               textBaseline: TextBaseline.alphabetic, | ||||||
|                               children: [ |                               children: [ | ||||||
|                                 AccountName( |                                 Flexible( | ||||||
|                                   account: user.value!, |                                   child: AccountName( | ||||||
|                                   style: TextStyle( |                                     account: user.value!, | ||||||
|                                     fontSize: 16, |                                     style: TextStyle( | ||||||
|                                     fontWeight: FontWeight.bold, |                                       fontSize: 16, | ||||||
|  |                                       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, | ||||||
|                             ), |                             ), | ||||||
| @@ -158,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: () { | ||||||
| @@ -176,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: () { | ||||||
| @@ -236,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(), | ||||||
| @@ -389,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,47 +88,166 @@ 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( | ||||||
|     return AppScaffold( |           title: Text('levelingProgress'.tr()), | ||||||
|       appBar: AppBar(title: Text('levelingProgress'.tr())), |           bottom: TabBar( | ||||||
|       body: SingleChildScrollView( |             tabs: [ | ||||||
|         padding: getTabbedPadding(context, horizontal: 20, vertical: 20), |               Tab( | ||||||
|         child: Center( |                 child: Text( | ||||||
|           child: ConstrainedBox( |                   'leveling'.tr(), | ||||||
|             constraints: const BoxConstraints(maxWidth: 480), |                   textAlign: TextAlign.center, | ||||||
|             child: Column( |                   style: TextStyle( | ||||||
|               crossAxisAlignment: CrossAxisAlignment.stretch, |                     color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|               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), |               ), | ||||||
|  |               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), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|                 // Stairs visualization with fixed height and horizontal scroll |   Widget _buildLevelingTab( | ||||||
|                 _buildLevelStairs(context, currentLevel), |     BuildContext context, | ||||||
|  |     WidgetRef ref, | ||||||
|  |     SnAccount user, | ||||||
|  |   ) { | ||||||
|  |     final currentLevel = user.profile.level; | ||||||
|  |     final currentExp = user.profile.experience; | ||||||
|  |     final progress = user.profile.levelingProgress; | ||||||
|  |  | ||||||
|                 const Gap(24), |     return Center( | ||||||
|  |       child: Container( | ||||||
|  |         padding: const EdgeInsets.symmetric(horizontal: 20), | ||||||
|  |         constraints: const BoxConstraints(maxWidth: 480), | ||||||
|  |         child: CustomScrollView( | ||||||
|  |           slivers: [ | ||||||
|  |             const SliverGap(20), | ||||||
|  |  | ||||||
|                 // Membership section |             // Current Progress Card | ||||||
|                 _buildMembershipSection(context, ref, stellarSubscription), |             SliverToBoxAdapter( | ||||||
|                 const Gap(16), |               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), | ||||||
|  |       child: Center( | ||||||
|  |         child: ConstrainedBox( | ||||||
|  |           constraints: const BoxConstraints(maxWidth: 480), | ||||||
|  |           child: Column( | ||||||
|  |             crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |             children: [ | ||||||
|  |               _buildMembershipSection(context, ref, stellarSubscription), | ||||||
|  |               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 | ||||||
|   | |||||||
| @@ -14,7 +14,6 @@ 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_devices.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'; | ||||||
| @@ -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,51 +438,19 @@ 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) { |       return Column( | ||||||
|         // Two-column layout for wide screens |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|         return Row( |         children: [ | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |           _SettingsSection( | ||||||
|           children: [ |             title: 'accountSecurityTitle', | ||||||
|             Expanded( |             children: securitySettings, | ||||||
|               child: Column( |           ), | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |           _SettingsSection( | ||||||
|                 children: [ |             title: 'accountDangerZoneTitle', | ||||||
|                   _SettingsSection( |             children: dangerZoneSettings, | ||||||
|                     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( |  | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|           children: [ |  | ||||||
|             _SettingsSection( |  | ||||||
|               title: 'accountSecurityTitle', |  | ||||||
|               children: securitySettings, |  | ||||||
|             ), |  | ||||||
|             _SettingsSection( |  | ||||||
|               title: 'accountDangerZoneTitle', |  | ||||||
|               children: dangerZoneSettings, |  | ||||||
|             ), |  | ||||||
|           ], |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return AppScaffold( |     return AppScaffold( | ||||||
|   | |||||||
| @@ -21,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}); | ||||||
| @@ -97,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 { | ||||||
| @@ -111,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); | ||||||
| @@ -291,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( | ||||||
|   | |||||||
| @@ -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/account_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,17 +196,25 @@ class AccountConnectionNewSheet extends HookConsumerWidget { | |||||||
|         case 'github': |         case 'github': | ||||||
|         case 'discord': |         case 'discord': | ||||||
|         case 'afdian': |         case 'afdian': | ||||||
|           await Navigator.of(context, rootNavigator: true).push( |           if (kIsWeb) { | ||||||
|             MaterialPageRoute( |             final serverUrl = ref.watch(serverUrlProvider); | ||||||
|               builder: |             final accessToken = ref.watch(tokenProvider); | ||||||
|                   (context) => OidcScreen( |             launchUrlString( | ||||||
|                     provider: selectedProvider.value.toLowerCase(), |               '$serverUrl/id/auth/login/${selectedProvider.value}?tk=${accessToken!.token}', | ||||||
|                     title: |             ); | ||||||
|                         'Connect with ${selectedProvider.value.capitalizeEachWord()}', |           } else { | ||||||
|                   ), |             await Navigator.of(context, rootNavigator: true).push( | ||||||
|             ), |               MaterialPageRoute( | ||||||
|           ); |                 builder: | ||||||
|           if (context.mounted) Navigator.pop(context, true); |                     (context) => OidcScreen( | ||||||
|  |                       provider: selectedProvider.value.toLowerCase(), | ||||||
|  |                       title: | ||||||
|  |                           'Connect with ${selectedProvider.value.capitalizeEachWord()}', | ||||||
|  |                     ), | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |             if (context.mounted) Navigator.pop(context, true); | ||||||
|  |           } | ||||||
|           break; |           break; | ||||||
|         default: |         default: | ||||||
|           showSnackBar('accountConnectionAddError'.tr()); |           showSnackBar('accountConnectionAddError'.tr()); | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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: [ | ||||||
|   | |||||||
| @@ -700,45 +700,48 @@ 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), | ||||||
|         Row( |         if (!kIsWeb) | ||||||
|           spacing: 6, |           Row( | ||||||
|           crossAxisAlignment: CrossAxisAlignment.center, |             spacing: 6, | ||||||
|           children: <Widget>[ |             crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|             Text("loginOr").tr().fontSize(11).opacity(0.85), |             children: <Widget>[ | ||||||
|             const Gap(8), |               Text("loginOr").tr().fontSize(11).opacity(0.85), | ||||||
|             Spacer(), |               const Gap(8), | ||||||
|             IconButton.filledTonal( |               Spacer(), | ||||||
|               onPressed: () => withOidc('github'), |               IconButton.filledTonal( | ||||||
|               padding: EdgeInsets.zero, |                 onPressed: () => withOidc('github'), | ||||||
|               icon: getProviderIcon( |                 padding: EdgeInsets.zero, | ||||||
|                 "github", |                 icon: getProviderIcon( | ||||||
|                 size: 16, |                   "github", | ||||||
|                 color: Theme.of(context).colorScheme.onPrimaryContainer, |                   size: 16, | ||||||
|  |                   color: Theme.of(context).colorScheme.onPrimaryContainer, | ||||||
|  |                 ), | ||||||
|  |                 tooltip: 'GitHub', | ||||||
|               ), |               ), | ||||||
|               tooltip: 'GitHub', |               IconButton.filledTonal( | ||||||
|             ), |                 onPressed: () => withOidc('google'), | ||||||
|             IconButton.filledTonal( |                 padding: EdgeInsets.zero, | ||||||
|               onPressed: () => withOidc('google'), |                 icon: getProviderIcon( | ||||||
|               padding: EdgeInsets.zero, |                   "google", | ||||||
|               icon: getProviderIcon( |                   size: 16, | ||||||
|                 "google", |                   color: Theme.of(context).colorScheme.onPrimaryContainer, | ||||||
|                 size: 16, |                 ), | ||||||
|                 color: Theme.of(context).colorScheme.onPrimaryContainer, |                 tooltip: 'Google', | ||||||
|               ), |               ), | ||||||
|               tooltip: 'Google', |               IconButton.filledTonal( | ||||||
|             ), |                 onPressed: withApple, | ||||||
|             IconButton.filledTonal( |                 padding: EdgeInsets.zero, | ||||||
|               onPressed: withApple, |                 icon: getProviderIcon( | ||||||
|               padding: EdgeInsets.zero, |                   "apple", | ||||||
|               icon: getProviderIcon( |                   size: 16, | ||||||
|                 "apple", |                   color: Theme.of(context).colorScheme.onPrimaryContainer, | ||||||
|                 size: 16, |                 ), | ||||||
|                 color: Theme.of(context).colorScheme.onPrimaryContainer, |                 tooltip: 'Apple Account', | ||||||
|               ), |               ), | ||||||
|               tooltip: 'Apple Account', |             ], | ||||||
|             ), |           ).padding(horizontal: 8, vertical: 8) | ||||||
|           ], |         else | ||||||
|         ).padding(horizontal: 8, vertical: 8), |           const Gap(12), | ||||||
|         Row( |         Row( | ||||||
|           mainAxisAlignment: MainAxisAlignment.spaceBetween, |           mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|           children: [ |           children: [ | ||||||
|   | |||||||
| @@ -79,33 +79,38 @@ class ChatRoomListTile extends HookConsumerWidget { | |||||||
|                     color: Theme.of(context).colorScheme.primary, |                     color: Theme.of(context).colorScheme.primary, | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|               Row( |               if (data.lastMessage == null) | ||||||
|                 spacing: 4, |                 Text(room.description ?? 'descriptionNone'.tr(), maxLines: 1) | ||||||
|                 children: [ |               else | ||||||
|                   Badge( |                 Row( | ||||||
|                     label: Text(data.lastMessage.sender.account.nick), |                   spacing: 4, | ||||||
|                     textColor: Theme.of(context).colorScheme.onPrimary, |                   children: [ | ||||||
|                     backgroundColor: Theme.of(context).colorScheme.primary, |                     Badge( | ||||||
|                   ), |                       label: Text(data.lastMessage!.sender.account.nick), | ||||||
|                   Expanded( |                       textColor: Theme.of(context).colorScheme.onPrimary, | ||||||
|                     child: Text( |                       backgroundColor: Theme.of(context).colorScheme.primary, | ||||||
|                       (data.lastMessage.content?.isNotEmpty ?? false) |  | ||||||
|                           ? data.lastMessage.content! |  | ||||||
|                           : 'messageNone'.tr(), |  | ||||||
|                       maxLines: 1, |  | ||||||
|                       overflow: TextOverflow.ellipsis, |  | ||||||
|                       style: Theme.of(context).textTheme.bodySmall, |  | ||||||
|                     ), |                     ), | ||||||
|                   ), |                     Expanded( | ||||||
|                   Align( |                       child: Text( | ||||||
|                     alignment: Alignment.centerRight, |                         (data.lastMessage!.content?.isNotEmpty ?? false) | ||||||
|                     child: Text( |                             ? data.lastMessage!.content! | ||||||
|                       RelativeTime(context).format(data.lastMessage.createdAt), |                             : 'messageNone'.tr(), | ||||||
|                       style: Theme.of(context).textTheme.bodySmall, |                         maxLines: 1, | ||||||
|  |                         overflow: TextOverflow.ellipsis, | ||||||
|  |                         style: Theme.of(context).textTheme.bodySmall, | ||||||
|  |                       ), | ||||||
|                     ), |                     ), | ||||||
|                   ), |                     Align( | ||||||
|                 ], |                       alignment: Alignment.centerRight, | ||||||
|               ), |                       child: Text( | ||||||
|  |                         RelativeTime( | ||||||
|  |                           context, | ||||||
|  |                         ).format(data.lastMessage!.createdAt), | ||||||
|  |                         style: Theme.of(context).textTheme.bodySmall, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|             ], |             ], | ||||||
|           ); |           ); | ||||||
|         }, |         }, | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import "dart:developer" as developer; | |||||||
| import "dart:io"; | import "dart:io"; | ||||||
| import "package:dio/dio.dart"; | import "package:dio/dio.dart"; | ||||||
| import "package:easy_localization/easy_localization.dart"; | import "package:easy_localization/easy_localization.dart"; | ||||||
|  | import "package:file_picker/file_picker.dart"; | ||||||
| import "package:flutter/foundation.dart"; | import "package:flutter/foundation.dart"; | ||||||
| import "package:flutter/material.dart"; | import "package:flutter/material.dart"; | ||||||
| import "package:go_router/go_router.dart"; | import "package:go_router/go_router.dart"; | ||||||
| @@ -72,6 +73,207 @@ class _AppLifecycleObserver extends WidgetsBindingObserver { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class _PublicRoomPreview extends HookConsumerWidget { | ||||||
|  |   final String id; | ||||||
|  |   final SnChatRoom room; | ||||||
|  |  | ||||||
|  |   const _PublicRoomPreview({required this.id, required this.room}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final messages = ref.watch(messagesNotifierProvider(id)); | ||||||
|  |     final messagesNotifier = ref.read(messagesNotifierProvider(id).notifier); | ||||||
|  |     final scrollController = useScrollController(); | ||||||
|  |  | ||||||
|  |     final listController = useMemoized(() => ListController(), []); | ||||||
|  |  | ||||||
|  |     var isLoading = false; | ||||||
|  |  | ||||||
|  |     // Add scroll listener for pagination | ||||||
|  |     useEffect(() { | ||||||
|  |       void onScroll() { | ||||||
|  |         if (scrollController.position.pixels >= | ||||||
|  |             scrollController.position.maxScrollExtent - 200) { | ||||||
|  |           if (isLoading) return; | ||||||
|  |           isLoading = true; | ||||||
|  |           messagesNotifier.loadMore().then((_) => isLoading = false); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       scrollController.addListener(onScroll); | ||||||
|  |       return () => scrollController.removeListener(onScroll); | ||||||
|  |     }, [scrollController]); | ||||||
|  |  | ||||||
|  |     Widget chatMessageListWidget(List<LocalChatMessage> messageList) => | ||||||
|  |         SuperListView.builder( | ||||||
|  |           listController: listController, | ||||||
|  |           padding: EdgeInsets.symmetric(vertical: 16), | ||||||
|  |           controller: scrollController, | ||||||
|  |           reverse: true, // Show newest messages at the bottom | ||||||
|  |           itemCount: messageList.length, | ||||||
|  |           findChildIndexCallback: (key) { | ||||||
|  |             final valueKey = key as ValueKey; | ||||||
|  |             final messageId = valueKey.value as String; | ||||||
|  |             return messageList.indexWhere((m) => m.id == messageId); | ||||||
|  |           }, | ||||||
|  |           extentEstimation: (_, _) => 40, | ||||||
|  |           itemBuilder: (context, index) { | ||||||
|  |             final message = messageList[index]; | ||||||
|  |             final nextMessage = | ||||||
|  |                 index < messageList.length - 1 ? messageList[index + 1] : null; | ||||||
|  |             final isLastInGroup = | ||||||
|  |                 nextMessage == null || | ||||||
|  |                 nextMessage.senderId != message.senderId || | ||||||
|  |                 nextMessage.createdAt | ||||||
|  |                         .difference(message.createdAt) | ||||||
|  |                         .inMinutes | ||||||
|  |                         .abs() > | ||||||
|  |                     3; | ||||||
|  |  | ||||||
|  |             return MessageItem( | ||||||
|  |               message: message, | ||||||
|  |               isCurrentUser: false, // User is not a member, so not current user | ||||||
|  |               onAction: null, // No actions allowed in preview mode | ||||||
|  |               onJump: (_) {}, // No jump functionality in preview | ||||||
|  |               progress: null, | ||||||
|  |               showAvatar: isLastInGroup, | ||||||
|  |             ); | ||||||
|  |           }, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |     final compactHeader = isWideScreen(context); | ||||||
|  |  | ||||||
|  |     Widget comfortHeaderWidget() => Column( | ||||||
|  |       spacing: 4, | ||||||
|  |       mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |       children: [ | ||||||
|  |         SizedBox( | ||||||
|  |           height: 26, | ||||||
|  |           width: 26, | ||||||
|  |           child: | ||||||
|  |               (room.type == 1 && room.picture?.id == null) | ||||||
|  |                   ? SplitAvatarWidget( | ||||||
|  |                     filesId: | ||||||
|  |                         room.members! | ||||||
|  |                             .map((e) => e.account.profile.picture?.id) | ||||||
|  |                             .toList(), | ||||||
|  |                   ) | ||||||
|  |                   : room.picture?.id != null | ||||||
|  |                   ? ProfilePictureWidget( | ||||||
|  |                     fileId: room.picture?.id, | ||||||
|  |                     fallbackIcon: Symbols.chat, | ||||||
|  |                   ) | ||||||
|  |                   : CircleAvatar( | ||||||
|  |                     child: Text( | ||||||
|  |                       room.name![0].toUpperCase(), | ||||||
|  |                       style: const TextStyle(fontSize: 12), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |         ), | ||||||
|  |         Text( | ||||||
|  |           (room.type == 1 && room.name == null) | ||||||
|  |               ? room.members!.map((e) => e.account.nick).join(', ') | ||||||
|  |               : room.name!, | ||||||
|  |         ).fontSize(15), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     Widget compactHeaderWidget() => Row( | ||||||
|  |       spacing: 8, | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |       children: [ | ||||||
|  |         SizedBox( | ||||||
|  |           height: 26, | ||||||
|  |           width: 26, | ||||||
|  |           child: | ||||||
|  |               (room.type == 1 && room.picture?.id == null) | ||||||
|  |                   ? SplitAvatarWidget( | ||||||
|  |                     filesId: | ||||||
|  |                         room.members! | ||||||
|  |                             .map((e) => e.account.profile.picture?.id) | ||||||
|  |                             .toList(), | ||||||
|  |                   ) | ||||||
|  |                   : room.picture?.id != null | ||||||
|  |                   ? ProfilePictureWidget( | ||||||
|  |                     fileId: room.picture?.id, | ||||||
|  |                     fallbackIcon: Symbols.chat, | ||||||
|  |                   ) | ||||||
|  |                   : CircleAvatar( | ||||||
|  |                     child: Text( | ||||||
|  |                       room.name![0].toUpperCase(), | ||||||
|  |                       style: const TextStyle(fontSize: 12), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |         ), | ||||||
|  |         Text( | ||||||
|  |           (room.type == 1 && room.name == null) | ||||||
|  |               ? room.members!.map((e) => e.account.nick).join(', ') | ||||||
|  |               : room.name!, | ||||||
|  |         ).fontSize(19), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         leading: !compactHeader ? const Center(child: PageBackButton()) : null, | ||||||
|  |         automaticallyImplyLeading: false, | ||||||
|  |         toolbarHeight: compactHeader ? null : 64, | ||||||
|  |         title: compactHeader ? compactHeaderWidget() : comfortHeaderWidget(), | ||||||
|  |         actions: [ | ||||||
|  |           IconButton( | ||||||
|  |             icon: const Icon(Icons.more_vert), | ||||||
|  |             onPressed: () { | ||||||
|  |               context.pushNamed('chatDetail', pathParameters: {'id': id}); | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|  |           const Gap(8), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |       body: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |         children: [ | ||||||
|  |           Expanded( | ||||||
|  |             child: messages.when( | ||||||
|  |               data: | ||||||
|  |                   (messageList) => | ||||||
|  |                       messageList.isEmpty | ||||||
|  |                           ? Center(child: Text('No messages yet'.tr())) | ||||||
|  |                           : chatMessageListWidget(messageList), | ||||||
|  |               loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |               error: | ||||||
|  |                   (error, _) => ResponseErrorWidget( | ||||||
|  |                     error: error, | ||||||
|  |                     onRetry: () => messagesNotifier.loadInitial(), | ||||||
|  |                   ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           // Join button at the bottom for public rooms | ||||||
|  |           Container( | ||||||
|  |             padding: const EdgeInsets.all(16), | ||||||
|  |             child: FilledButton.tonalIcon( | ||||||
|  |               onPressed: () async { | ||||||
|  |                 try { | ||||||
|  |                   showLoadingModal(context); | ||||||
|  |                   final apiClient = ref.read(apiClientProvider); | ||||||
|  |                   await apiClient.post('/sphere/chat/${room.id}/members/me'); | ||||||
|  |                   ref.invalidate(chatroomIdentityProvider(id)); | ||||||
|  |                 } catch (err) { | ||||||
|  |                   showErrorAlert(err); | ||||||
|  |                 } finally { | ||||||
|  |                   if (context.mounted) hideLoadingModal(context); | ||||||
|  |                 } | ||||||
|  |               }, | ||||||
|  |               label: Text('chatJoin').tr(), | ||||||
|  |               icon: const Icon(Icons.add), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| @riverpod | @riverpod | ||||||
| class MessagesNotifier extends _$MessagesNotifier { | class MessagesNotifier extends _$MessagesNotifier { | ||||||
|   late final Dio _apiClient; |   late final Dio _apiClient; | ||||||
| @@ -82,6 +284,9 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|   final Map<String, LocalChatMessage> _pendingMessages = {}; |   final Map<String, LocalChatMessage> _pendingMessages = {}; | ||||||
|   final Map<String, Map<int, double>> _fileUploadProgress = {}; |   final Map<String, Map<int, double>> _fileUploadProgress = {}; | ||||||
|   int? _totalCount; |   int? _totalCount; | ||||||
|  |   String? _searchQuery; | ||||||
|  |   bool? _withLinks; | ||||||
|  |   bool? _withAttachments; | ||||||
|  |  | ||||||
|   late final String _roomId; |   late final String _roomId; | ||||||
|   int _currentPage = 0; |   int _currentPage = 0; | ||||||
| @@ -96,28 +301,42 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     _database = ref.watch(databaseProvider); |     _database = ref.watch(databaseProvider); | ||||||
|     final room = await ref.watch(chatroomProvider(roomId).future); |     final room = await ref.watch(chatroomProvider(roomId).future); | ||||||
|     final identity = await ref.watch(chatroomIdentityProvider(roomId).future); |     final identity = await ref.watch(chatroomIdentityProvider(roomId).future); | ||||||
|     if (room == null || identity == null) { |  | ||||||
|       throw Exception('Room or identity not found'); |     if (room == null) { | ||||||
|  |       throw Exception('Room not found'); | ||||||
|     } |     } | ||||||
|     _room = room; |     _room = room; | ||||||
|     _identity = identity; |  | ||||||
|  |     // Allow building even if identity is null for public rooms | ||||||
|  |     if (identity != null) { | ||||||
|  |       _identity = identity; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     developer.log( |     developer.log( | ||||||
|       'MessagesNotifier built for room $roomId', |       'MessagesNotifier built for room $roomId', | ||||||
|       name: 'MessagesNotifier', |       name: 'MessagesNotifier', | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     ref.listen(appLifecycleStateProvider, (_, next) { |     // Only setup sync and lifecycle listeners if user is a member | ||||||
|       if (next.hasValue && next.value == AppLifecycleState.resumed) { |     if (identity != null) { | ||||||
|         developer.log( |       ref.listen(appLifecycleStateProvider, (_, next) { | ||||||
|           'App resumed, syncing messages', |         if (next.hasValue && next.value == AppLifecycleState.resumed) { | ||||||
|           name: 'MessagesNotifier', |           developer.log( | ||||||
|         ); |             'App resumed, syncing messages', | ||||||
|         syncMessages(); |             name: 'MessagesNotifier', | ||||||
|       } |           ); | ||||||
|     }); |           syncMessages(); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return await loadInitial(); |     loadInitial(); | ||||||
|  |     return []; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   List<LocalChatMessage> _sortMessages(List<LocalChatMessage> messages) { | ||||||
|  |     messages.sort((a, b) => b.createdAt.compareTo(a.createdAt)); | ||||||
|  |     return messages; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<List<LocalChatMessage>> _getCachedMessages({ |   Future<List<LocalChatMessage>> _getCachedMessages({ | ||||||
| @@ -128,13 +347,32 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|       'Getting cached messages from offset $offset, take $take', |       'Getting cached messages from offset $offset, take $take', | ||||||
|       name: 'MessagesNotifier', |       name: 'MessagesNotifier', | ||||||
|     ); |     ); | ||||||
|     final dbMessages = await _database.getMessagesForRoom( |     final List<LocalChatMessage> dbMessages; | ||||||
|       _roomId, |     if (_searchQuery != null && _searchQuery!.isNotEmpty) { | ||||||
|       offset: offset, |       dbMessages = await _database.searchMessages(_roomId, _searchQuery ?? ''); | ||||||
|       limit: take, |     } else { | ||||||
|     ); |       final chatMessagesFromDb = await _database.getMessagesForRoom( | ||||||
|     final dbLocalMessages = |         _roomId, | ||||||
|         dbMessages.map(_database.companionToMessage).toList(); |         offset: offset, | ||||||
|  |         limit: take, | ||||||
|  |       ); | ||||||
|  |       dbMessages = | ||||||
|  |           chatMessagesFromDb.map(_database.companionToMessage).toList(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     List<LocalChatMessage> filteredMessages = dbMessages; | ||||||
|  |  | ||||||
|  |     if (_withLinks == true) { | ||||||
|  |       filteredMessages = | ||||||
|  |           filteredMessages.where((msg) => _hasLink(msg)).toList(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (_withAttachments == true) { | ||||||
|  |       filteredMessages = | ||||||
|  |           filteredMessages.where((msg) => _hasAttachment(msg)).toList(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     final dbLocalMessages = filteredMessages; | ||||||
|  |  | ||||||
|     if (offset == 0) { |     if (offset == 0) { | ||||||
|       final pendingForRoom = |       final pendingForRoom = | ||||||
| @@ -143,7 +381,7 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|               .toList(); |               .toList(); | ||||||
|  |  | ||||||
|       final allMessages = [...pendingForRoom, ...dbLocalMessages]; |       final allMessages = [...pendingForRoom, ...dbLocalMessages]; | ||||||
|       allMessages.sort((a, b) => b.createdAt.compareTo(a.createdAt)); |       _sortMessages(allMessages); // Use the helper function | ||||||
|  |  | ||||||
|       final uniqueMessages = <LocalChatMessage>[]; |       final uniqueMessages = <LocalChatMessage>[]; | ||||||
|       final seenIds = <String>{}; |       final seenIds = <String>{}; | ||||||
| @@ -218,7 +456,7 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     _isSyncing = true; |     _isSyncing = true; | ||||||
|  |  | ||||||
|     developer.log('Starting message sync', name: 'MessagesNotifier'); |     developer.log('Starting message sync', name: 'MessagesNotifier'); | ||||||
|     ref.read(isSyncingProvider.notifier).state = true; |     Future.microtask(() => ref.read(isSyncingProvider.notifier).state = true); | ||||||
|     try { |     try { | ||||||
|       final dbMessages = await _database.getMessagesForRoom( |       final dbMessages = await _database.getMessagesForRoom( | ||||||
|         _room.id, |         _room.id, | ||||||
| @@ -279,7 +517,9 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|       showErrorAlert(err); |       showErrorAlert(err); | ||||||
|     } finally { |     } finally { | ||||||
|       developer.log('Finished message sync', name: 'MessagesNotifier'); |       developer.log('Finished message sync', name: 'MessagesNotifier'); | ||||||
|       ref.read(isSyncingProvider.notifier).state = false; |       Future.microtask( | ||||||
|  |         () => ref.read(isSyncingProvider.notifier).state = false, | ||||||
|  |       ); | ||||||
|       _isSyncing = false; |       _isSyncing = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -290,7 +530,9 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     bool synced = false, |     bool synced = false, | ||||||
|   }) async { |   }) async { | ||||||
|     try { |     try { | ||||||
|       if (offset == 0 && !synced) { |       if (offset == 0 && | ||||||
|  |           !synced && | ||||||
|  |           (_searchQuery == null || _searchQuery!.isEmpty)) { | ||||||
|         _fetchAndCacheMessages(offset: 0, take: take).catchError((_) { |         _fetchAndCacheMessages(offset: 0, take: take).catchError((_) { | ||||||
|           return <LocalChatMessage>[]; |           return <LocalChatMessage>[]; | ||||||
|         }); |         }); | ||||||
| @@ -305,7 +547,11 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|         return localMessages; |         return localMessages; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       return await _fetchAndCacheMessages(offset: offset, take: take); |       if (_searchQuery == null || _searchQuery!.isEmpty) { | ||||||
|  |         return await _fetchAndCacheMessages(offset: offset, take: take); | ||||||
|  |       } else { | ||||||
|  |         return []; // If searching, and no local messages, don't fetch from network | ||||||
|  |       } | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       final localMessages = await _getCachedMessages( |       final localMessages = await _getCachedMessages( | ||||||
|         offset: offset, |         offset: offset, | ||||||
| @@ -319,13 +565,15 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<List<LocalChatMessage>> loadInitial() async { |   Future<void> loadInitial() async { | ||||||
|     developer.log('Loading initial messages', name: 'MessagesNotifier'); |     developer.log('Loading initial messages', name: 'MessagesNotifier'); | ||||||
|     syncMessages(); |     if (_searchQuery == null || _searchQuery!.isEmpty) { | ||||||
|  |       syncMessages(); | ||||||
|  |     } | ||||||
|     final messages = await _getCachedMessages(offset: 0, take: 100); |     final messages = await _getCachedMessages(offset: 0, take: 100); | ||||||
|     _currentPage = 0; |     _currentPage = 0; | ||||||
|     _hasMore = messages.length == _pageSize; |     _hasMore = messages.length == _pageSize; | ||||||
|     return messages; |     state = AsyncValue.data(messages); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> loadMore() async { |   Future<void> loadMore() async { | ||||||
| @@ -344,7 +592,9 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|         _hasMore = false; |         _hasMore = false; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       state = AsyncValue.data([...currentMessages, ...newMessages]); |       state = AsyncValue.data( | ||||||
|  |         _sortMessages([...currentMessages, ...newMessages]), | ||||||
|  |       ); | ||||||
|     } catch (err, stackTrace) { |     } catch (err, stackTrace) { | ||||||
|       developer.log( |       developer.log( | ||||||
|         'Error loading more messages', |         'Error loading more messages', | ||||||
| @@ -455,10 +705,13 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|  |  | ||||||
|       final currentMessages = state.value ?? []; |       final currentMessages = state.value ?? []; | ||||||
|       if (editingTo != null) { |       if (editingTo != null) { | ||||||
|         final newMessages = currentMessages |         final newMessages = | ||||||
|             .where((m) => m.id != localMessage.id) // remove pending message |             currentMessages | ||||||
|             .map((m) => m.id == editingTo.id ? updatedMessage : m) // update original message |                 .where((m) => m.id != localMessage.id) // remove pending message | ||||||
|             .toList(); |                 .map( | ||||||
|  |                   (m) => m.id == editingTo.id ? updatedMessage : m, | ||||||
|  |                 ) // update original message | ||||||
|  |                 .toList(); | ||||||
|         state = AsyncValue.data(newMessages); |         state = AsyncValue.data(newMessages); | ||||||
|       } else { |       } else { | ||||||
|         final newMessages = |         final newMessages = | ||||||
| @@ -566,7 +819,7 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|             } |             } | ||||||
|             return m; |             return m; | ||||||
|           }).toList(); |           }).toList(); | ||||||
|       state = AsyncValue.data(newMessages); |       state = AsyncValue.data(_sortMessages(newMessages)); | ||||||
|       showErrorAlert(e); |       showErrorAlert(e); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -626,7 +879,7 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     if (index >= 0) { |     if (index >= 0) { | ||||||
|       final newList = [...currentMessages]; |       final newList = [...currentMessages]; | ||||||
|       newList[index] = updatedMessage; |       newList[index] = updatedMessage; | ||||||
|       state = AsyncValue.data(newList); |       state = AsyncValue.data(_sortMessages(newList)); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -686,6 +939,20 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void searchMessages(String query, {bool? withLinks, bool? withAttachments}) { | ||||||
|  |     _searchQuery = query.trim(); | ||||||
|  |     _withLinks = withLinks; | ||||||
|  |     _withAttachments = withAttachments; | ||||||
|  |     loadInitial(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void clearSearch() { | ||||||
|  |     _searchQuery = null; | ||||||
|  |     _withLinks = null; | ||||||
|  |     _withAttachments = null; | ||||||
|  |     loadInitial(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   Future<LocalChatMessage?> fetchMessageById(String messageId) async { |   Future<LocalChatMessage?> fetchMessageById(String messageId) async { | ||||||
|     developer.log( |     developer.log( | ||||||
|       'Fetching message by id $messageId', |       'Fetching message by id $messageId', | ||||||
| @@ -715,6 +982,18 @@ class MessagesNotifier extends _$MessagesNotifier { | |||||||
|       rethrow; |       rethrow; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   bool _hasLink(LocalChatMessage message) { | ||||||
|  |     final content = message.toRemoteMessage().content; | ||||||
|  |     if (content == null) return false; | ||||||
|  |     final urlRegex = RegExp(r'https?://[^\s/$.?#].[^\s]*'); | ||||||
|  |     return urlRegex.hasMatch(content); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool _hasAttachment(LocalChatMessage message) { | ||||||
|  |     final remoteMessage = message.toRemoteMessage(); | ||||||
|  |     return remoteMessage.attachments.isNotEmpty; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| class ChatRoomScreen extends HookConsumerWidget { | class ChatRoomScreen extends HookConsumerWidget { | ||||||
| @@ -734,57 +1013,77 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|       ); |       ); | ||||||
|     } else if (chatIdentity.value == null) { |     } else if (chatIdentity.value == null) { | ||||||
|       // Identity was not found, user was not joined |       // Identity was not found, user was not joined | ||||||
|       return AppScaffold( |       return chatRoom.when( | ||||||
|         appBar: AppBar(leading: const PageBackButton()), |         data: (room) { | ||||||
|         body: Center( |           if (room!.isPublic) { | ||||||
|           child: |             // Show public room preview with messages but no input | ||||||
|               ConstrainedBox( |             return _PublicRoomPreview(id: id, room: room); | ||||||
|                 constraints: const BoxConstraints(maxWidth: 280), |           } else { | ||||||
|                 child: Column( |             // Show regular "not joined" screen for private rooms | ||||||
|                   crossAxisAlignment: CrossAxisAlignment.center, |             return AppScaffold( | ||||||
|                   mainAxisAlignment: MainAxisAlignment.center, |               appBar: AppBar(leading: const PageBackButton()), | ||||||
|                   children: [ |               body: Center( | ||||||
|                     Icon( |                 child: | ||||||
|                       chatRoom.value?.isCommunity == true |                     ConstrainedBox( | ||||||
|                           ? Symbols.person_add |                       constraints: const BoxConstraints(maxWidth: 280), | ||||||
|                           : Symbols.person_remove, |                       child: Column( | ||||||
|                       size: 36, |                         crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|                       fill: 1, |                         mainAxisAlignment: MainAxisAlignment.center, | ||||||
|                     ).padding(bottom: 4), |                         children: [ | ||||||
|                     Text('chatNotJoined').tr(), |                           Icon( | ||||||
|                     if (chatRoom.value?.isCommunity != true) |                             room.isCommunity == true | ||||||
|                       Text( |                                 ? Symbols.person_add | ||||||
|                         'chatUnableJoin', |                                 : Symbols.person_remove, | ||||||
|                         textAlign: TextAlign.center, |                             size: 36, | ||||||
|                       ).tr().bold() |                             fill: 1, | ||||||
|                     else |                           ).padding(bottom: 4), | ||||||
|                       FilledButton.tonalIcon( |                           Text('chatNotJoined').tr(), | ||||||
|                         onPressed: () async { |                           if (room.isCommunity != true) | ||||||
|                           try { |                             Text( | ||||||
|                             showLoadingModal(context); |                               'chatUnableJoin', | ||||||
|                             final apiClient = ref.read(apiClientProvider); |                               textAlign: TextAlign.center, | ||||||
|                             if (chatRoom.value == null) { |                             ).tr().bold() | ||||||
|                               hideLoadingModal(context); |                           else | ||||||
|                               return; |                             FilledButton.tonalIcon( | ||||||
|                             } |                               onPressed: () async { | ||||||
|  |                                 try { | ||||||
|                             await apiClient.post( |                                   showLoadingModal(context); | ||||||
|                               '/sphere/chat/${chatRoom.value!.id}/members/me', |                                   final apiClient = ref.read(apiClientProvider); | ||||||
|                             ); |                                   await apiClient.post( | ||||||
|                             ref.invalidate(chatroomIdentityProvider(id)); |                                     '/sphere/chat/${room.id}/members/me', | ||||||
|                           } catch (err) { |                                   ); | ||||||
|                             showErrorAlert(err); |                                   ref.invalidate(chatroomIdentityProvider(id)); | ||||||
|                           } finally { |                                 } catch (err) { | ||||||
|                             if (context.mounted) hideLoadingModal(context); |                                   showErrorAlert(err); | ||||||
|                           } |                                 } finally { | ||||||
|                         }, |                                   if (context.mounted) { | ||||||
|                         label: Text('chatJoin').tr(), |                                     hideLoadingModal(context); | ||||||
|                         icon: const Icon(Icons.add), |                                   } | ||||||
|                       ).padding(top: 8), |                                 } | ||||||
|                   ], |                               }, | ||||||
|                 ), |                               label: Text('chatJoin').tr(), | ||||||
|               ).center(), |                               icon: const Icon(Icons.add), | ||||||
|         ), |                             ).padding(top: 8), | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ).center(), | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         loading: | ||||||
|  |             () => AppScaffold( | ||||||
|  |               appBar: AppBar(leading: const PageBackButton()), | ||||||
|  |               body: CircularProgressIndicator().center(), | ||||||
|  |             ), | ||||||
|  |         error: | ||||||
|  |             (error, _) => AppScaffold( | ||||||
|  |               appBar: AppBar(leading: const PageBackButton()), | ||||||
|  |               body: ResponseErrorWidget( | ||||||
|  |                 error: error, | ||||||
|  |                 onRetry: () => ref.refresh(chatroomProvider(id)), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -953,26 +1252,32 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|     }, [id]); |     }, [id]); | ||||||
|  |  | ||||||
|     Future<void> pickPhotoMedia() async { |     Future<void> pickPhotoMedia() async { | ||||||
|       final result = await ref |       final result = await FilePicker.platform.pickFiles( | ||||||
|           .watch(imagePickerProvider) |         type: FileType.image, | ||||||
|           .pickMultiImage(requestFullMetadata: true); |         allowMultiple: true, | ||||||
|       if (result.isEmpty) return; |         allowCompression: false, | ||||||
|  |       ); | ||||||
|  |       if (result == null || result.count == 0) return; | ||||||
|       attachments.value = [ |       attachments.value = [ | ||||||
|         ...attachments.value, |         ...attachments.value, | ||||||
|         ...result.map( |         ...result.files.map( | ||||||
|           (e) => UniversalFile(data: e, type: UniversalFileType.image), |           (e) => UniversalFile(data: e.xFile, type: UniversalFileType.image), | ||||||
|         ), |         ), | ||||||
|       ]; |       ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Future<void> pickVideoMedia() async { |     Future<void> pickVideoMedia() async { | ||||||
|       final result = await ref |       final result = await FilePicker.platform.pickFiles( | ||||||
|           .watch(imagePickerProvider) |         type: FileType.video, | ||||||
|           .pickVideo(source: ImageSource.gallery); |         allowMultiple: true, | ||||||
|       if (result == null) return; |         allowCompression: false, | ||||||
|  |       ); | ||||||
|  |       if (result == null || result.count == 0) return; | ||||||
|       attachments.value = [ |       attachments.value = [ | ||||||
|         ...attachments.value, |         ...attachments.value, | ||||||
|         UniversalFile(data: result, type: UniversalFileType.video), |         ...result.files.map( | ||||||
|  |           (e) => UniversalFile(data: e.xFile, type: UniversalFileType.video), | ||||||
|  |         ), | ||||||
|       ]; |       ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1089,6 +1394,8 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  |     const messageKeyPrefix = 'message-'; | ||||||
|  |  | ||||||
|     Widget chatMessageListWidget(List<LocalChatMessage> messageList) => |     Widget chatMessageListWidget(List<LocalChatMessage> messageList) => | ||||||
|         SuperListView.builder( |         SuperListView.builder( | ||||||
|           listController: listController, |           listController: listController, | ||||||
| @@ -1098,7 +1405,9 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|           itemCount: messageList.length, |           itemCount: messageList.length, | ||||||
|           findChildIndexCallback: (key) { |           findChildIndexCallback: (key) { | ||||||
|             final valueKey = key as ValueKey; |             final valueKey = key as ValueKey; | ||||||
|             final messageId = valueKey.value as String; |             final messageId = (valueKey.value as String).substring( | ||||||
|  |               messageKeyPrefix.length, | ||||||
|  |             ); | ||||||
|             return messageList.indexWhere((m) => m.id == messageId); |             return messageList.indexWhere((m) => m.id == messageId); | ||||||
|           }, |           }, | ||||||
|           extentEstimation: (_, _) => 40, |           extentEstimation: (_, _) => 40, | ||||||
| @@ -1115,10 +1424,13 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|                         .abs() > |                         .abs() > | ||||||
|                     3; |                     3; | ||||||
|  |  | ||||||
|  |             final key = ValueKey('$messageKeyPrefix${message.id}'); | ||||||
|  |  | ||||||
|             return chatIdentity.when( |             return chatIdentity.when( | ||||||
|               skipError: true, |               skipError: true, | ||||||
|               data: |               data: | ||||||
|                   (identity) => MessageItem( |                   (identity) => MessageItem( | ||||||
|  |                     key: key, | ||||||
|                     message: message, |                     message: message, | ||||||
|                     isCurrentUser: identity?.id == message.senderId, |                     isCurrentUser: identity?.id == message.senderId, | ||||||
|                     onAction: (action) { |                     onAction: (action) { | ||||||
| @@ -1161,6 +1473,7 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|                   ), |                   ), | ||||||
|               loading: |               loading: | ||||||
|                   () => MessageItem( |                   () => MessageItem( | ||||||
|  |                     key: key, | ||||||
|                     message: message, |                     message: message, | ||||||
|                     isCurrentUser: false, |                     isCurrentUser: false, | ||||||
|                     onAction: null, |                     onAction: null, | ||||||
| @@ -1168,7 +1481,7 @@ class ChatRoomScreen extends HookConsumerWidget { | |||||||
|                     showAvatar: false, |                     showAvatar: false, | ||||||
|                     onJump: (_) {}, |                     onJump: (_) {}, | ||||||
|                   ), |                   ), | ||||||
|               error: (_, _) => const SizedBox.shrink(), |               error: (_, _) => SizedBox.shrink(key: key), | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|         ); |         ); | ||||||
| @@ -1549,7 +1862,7 @@ class _ChatInput extends HookConsumerWidget { | |||||||
|                   children: [ |                   children: [ | ||||||
|                     IconButton( |                     IconButton( | ||||||
|                       tooltip: 'stickers'.tr(), |                       tooltip: 'stickers'.tr(), | ||||||
|                       icon: const Icon(Symbols.emoji_symbols), |                       icon: const Icon(Symbols.add_reaction), | ||||||
|                       onPressed: () { |                       onPressed: () { | ||||||
|                         final size = MediaQuery.of(context).size; |                         final size = MediaQuery.of(context).size; | ||||||
|                         showStickerPickerPopover( |                         showStickerPickerPopover( | ||||||
| @@ -1659,8 +1972,13 @@ class _ChatInput extends HookConsumerWidget { | |||||||
|                           horizontal: 12, |                           horizontal: 12, | ||||||
|                           vertical: 4, |                           vertical: 4, | ||||||
|                         ), |                         ), | ||||||
|  |                         counterText: | ||||||
|  |                             messageController.text.length > 1024 | ||||||
|  |                                 ? '${messageController.text.length}/4096' | ||||||
|  |                                 : null, | ||||||
|                       ), |                       ), | ||||||
|                       maxLines: null, |                       maxLines: 3, | ||||||
|  |                       minLines: 1, | ||||||
|                       onTapOutside: |                       onTapOutside: | ||||||
|                           (_) => FocusManager.instance.primaryFocus?.unfocus(), |                           (_) => FocusManager.instance.primaryFocus?.unfocus(), | ||||||
|                     ), |                     ), | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ part of 'room.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$messagesNotifierHash() => r'32afe6ea24086d869cc47bd3389c8fd734409ca0'; | String _$messagesNotifierHash() => r'fc3b66dfb8dd3fc55d142dae5c5e7bdc67eca5d4'; | ||||||
|  |  | ||||||
| /// Copied from Dart SDK | /// Copied from Dart SDK | ||||||
| class _SystemHash { | class _SystemHash { | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ 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/account/status.dart'; | ||||||
| import 'package:island/widgets/alert.dart'; | import 'package:island/widgets/alert.dart'; | ||||||
| @@ -19,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}); | ||||||
| @@ -31,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', | ||||||
| @@ -131,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: () { | ||||||
| @@ -143,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))); | ||||||
| @@ -155,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))); | ||||||
| @@ -167,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))); | ||||||
| @@ -179,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))); | ||||||
| @@ -194,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), | ||||||
| @@ -238,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: [ | ||||||
| @@ -358,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(), | ||||||
| @@ -666,8 +716,11 @@ 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( | ||||||
|                         fileId: member.account.profile.picture?.id, |                         uname: member.account.name, | ||||||
|  |                         child: ProfilePictureWidget( | ||||||
|  |                           fileId: member.account.profile.picture?.id, | ||||||
|  |                         ), | ||||||
|                       ), |                       ), | ||||||
|                       title: Row( |                       title: Row( | ||||||
|                         spacing: 6, |                         spacing: 6, | ||||||
| @@ -848,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'; | ||||||
|   | |||||||
| @@ -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: [ | ||||||
|   | |||||||
| @@ -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,50 +15,98 @@ 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, | ||||||
|             onPressed: () { |               children: [ | ||||||
|               context.pushNamed( |                 Text('noCustomApps').tr(), | ||||||
|                 'developerAppNew', |                 const SizedBox(height: 16), | ||||||
|                 pathParameters: {'name': publisherName}, |                 ElevatedButton.icon( | ||||||
|               ); |                   onPressed: () { | ||||||
|             }, |                     context.pushNamed( | ||||||
|           ), |                       'developerAppNew', | ||||||
|         ], |                       pathParameters: { | ||||||
|       ), |                         'name': publisherName, | ||||||
|       body: apps.when( |                         'projectId': projectId, | ||||||
|         data: (data) { |                       }, | ||||||
|           if (data.isEmpty) { |                     ); | ||||||
|             return Center(child: Text('noCustomApps').tr()); |                   }, | ||||||
|           } |                   icon: const Icon(Symbols.add), | ||||||
|           return RefreshIndicator( |                   label: Text('createCustomApp').tr(), | ||||||
|             onRefresh: |                 ), | ||||||
|                 () => ref.refresh(customAppsProvider(publisherName).future), |               ], | ||||||
|             child: ListView.builder( |             ), | ||||||
|               padding: EdgeInsets.only(top: 4), |           ); | ||||||
|               itemCount: data.length, |         } | ||||||
|               itemBuilder: (context, index) { |         return RefreshIndicator( | ||||||
|                 final app = data[index]; |           onRefresh: | ||||||
|                 return Card( |               () => ref.refresh( | ||||||
|                   margin: const EdgeInsets.all(8.0), |                 customAppsProvider(publisherName, projectId).future, | ||||||
|  |               ), | ||||||
|  |           child: ListView.builder( | ||||||
|  |             padding: EdgeInsets.only(top: 4), | ||||||
|  |             itemCount: data.length, | ||||||
|  |             itemBuilder: (context, index) { | ||||||
|  |               final app = data[index]; | ||||||
|  |               return Card( | ||||||
|  |                 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,18 +203,21 @@ class CustomAppsScreen extends HookConsumerWidget { | |||||||
|                       ), |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ), |                   ), | ||||||
|                 ); |                 ), | ||||||
|               }, |               ); | ||||||
|             ), |             }, | ||||||
|           ); |           ), | ||||||
|         }, |         ); | ||||||
|         loading: () => const Center(child: CircularProgressIndicator()), |       }, | ||||||
|         error: |       loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|             (err, stack) => ResponseErrorWidget( |       error: | ||||||
|               error: err, |           (err, stack) => ResponseErrorWidget( | ||||||
|               onRetry: () => ref.invalidate(customAppsProvider(publisherName)), |             error: err, | ||||||
|             ), |             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 | ||||||
|   | |||||||
							
								
								
									
										161
									
								
								lib/screens/developers/bot_detail.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								lib/screens/developers/bot_detail.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | |||||||
|  | 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/models/bot.dart'; | ||||||
|  | import 'package:island/screens/developers/bot_keys.dart'; | ||||||
|  | import 'package:island/screens/developers/edit_bot.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:go_router/go_router.dart'; | ||||||
|  | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
|  | class BotDetailScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String botId; | ||||||
|  |  | ||||||
|  |   const BotDetailScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     required this.botId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final tabController = useTabController(initialLength: 2); | ||||||
|  |     final botData = ref.watch(botProvider(publisherName, projectId, botId)); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: Text(botData.value?.account.nick ?? 'botDetails'.tr()), | ||||||
|  |         actions: [ | ||||||
|  |           IconButton( | ||||||
|  |             icon: const Icon(Symbols.edit), | ||||||
|  |             onPressed: | ||||||
|  |                 botData.value == null | ||||||
|  |                     ? null | ||||||
|  |                     : () { | ||||||
|  |                       context.pushNamed( | ||||||
|  |                         'developerBotEdit', | ||||||
|  |                         pathParameters: { | ||||||
|  |                           'name': publisherName, | ||||||
|  |                           'projectId': projectId, | ||||||
|  |                           'id': botId, | ||||||
|  |                         }, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |         bottom: TabBar( | ||||||
|  |           controller: tabController, | ||||||
|  |           tabs: [ | ||||||
|  |             Tab( | ||||||
|  |               child: Text( | ||||||
|  |                 'overview'.tr(), | ||||||
|  |                 textAlign: TextAlign.center, | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             Tab( | ||||||
|  |               child: Text( | ||||||
|  |                 'keys'.tr(), | ||||||
|  |                 textAlign: TextAlign.center, | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |       body: botData.when( | ||||||
|  |         data: (bot) { | ||||||
|  |           if (bot == null) { | ||||||
|  |             return Center(child: Text('botNotFound'.tr())); | ||||||
|  |           } | ||||||
|  |           return TabBarView( | ||||||
|  |             controller: tabController, | ||||||
|  |             physics: const NeverScrollableScrollPhysics(), | ||||||
|  |             children: [ | ||||||
|  |               _BotOverview(bot: bot), | ||||||
|  |               BotKeysScreen( | ||||||
|  |                 publisherName: publisherName, | ||||||
|  |                 projectId: projectId, | ||||||
|  |                 botId: botId, | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |         loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |         error: | ||||||
|  |             (err, stack) => ResponseErrorWidget( | ||||||
|  |               error: err, | ||||||
|  |               onRetry: | ||||||
|  |                   () => ref.invalidate( | ||||||
|  |                     botProvider(publisherName, projectId, botId), | ||||||
|  |                   ), | ||||||
|  |             ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _BotOverview extends StatelessWidget { | ||||||
|  |   final Bot bot; | ||||||
|  |   const _BotOverview({required this.bot}); | ||||||
|  |  | ||||||
|  |   @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: | ||||||
|  |                       bot.account.profile.background != null | ||||||
|  |                           ? CloudFileWidget( | ||||||
|  |                             item: bot.account.profile.background!, | ||||||
|  |                             fit: BoxFit.cover, | ||||||
|  |                           ) | ||||||
|  |                           : const SizedBox.shrink(), | ||||||
|  |                 ), | ||||||
|  |                 Positioned( | ||||||
|  |                   left: 20, | ||||||
|  |                   bottom: -32, | ||||||
|  |                   child: ProfilePictureWidget( | ||||||
|  |                     fileId: bot.account.profile.picture?.id, | ||||||
|  |                     radius: 40, | ||||||
|  |                     fallbackIcon: Symbols.smart_toy, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ).padding(bottom: 32), | ||||||
|  |           ListTile(title: Text('name'.tr()), subtitle: Text(bot.account.name)), | ||||||
|  |           ListTile( | ||||||
|  |             title: Text('nickname'.tr()), | ||||||
|  |             subtitle: Text(bot.account.nick), | ||||||
|  |           ), | ||||||
|  |           ListTile(title: Text('slug'.tr()), subtitle: Text(bot.slug)), | ||||||
|  |           if (bot.account.profile.bio.isNotEmpty) | ||||||
|  |             ListTile( | ||||||
|  |               title: Text('bio'.tr()), | ||||||
|  |               subtitle: Text(bot.account.profile.bio), | ||||||
|  |             ), | ||||||
|  |         ], | ||||||
|  |       ).padding(bottom: 24), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										278
									
								
								lib/screens/developers/bot_keys.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								lib/screens/developers/bot_keys.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,278 @@ | |||||||
|  | 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:gap/gap.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/bot_key.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 'bot_keys.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<List<SnAccountApiKey>> botKeys( | ||||||
|  |   Ref ref, | ||||||
|  |   String publisherName, | ||||||
|  |   String projectId, | ||||||
|  |   String botId, | ||||||
|  | ) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await client.get( | ||||||
|  |     '/develop/developers/$publisherName/projects/$projectId/bots/$botId/keys', | ||||||
|  |   ); | ||||||
|  |   return (resp.data as List).map((e) => SnAccountApiKey.fromJson(e)).toList(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class BotKeysScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String botId; | ||||||
|  |  | ||||||
|  |   const BotKeysScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     required this.botId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final keys = ref.watch(botKeysProvider(publisherName, projectId, botId)); | ||||||
|  |     final keyNameController = useTextEditingController(); | ||||||
|  |  | ||||||
|  |     void showNewKeySheet(SnAccountApiKey newApiKey) { | ||||||
|  |       final token = newApiKey.key; | ||||||
|  |       if (token == null) return; | ||||||
|  |  | ||||||
|  |       showModalBottomSheet( | ||||||
|  |         context: context, | ||||||
|  |         isScrollControlled: true, | ||||||
|  |         builder: | ||||||
|  |             (context) => SheetScaffold( | ||||||
|  |               titleText: 'newKeyGenerated'.tr(), | ||||||
|  |               child: Padding( | ||||||
|  |                 padding: const EdgeInsets.all(20.0), | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                   mainAxisSize: MainAxisSize.min, | ||||||
|  |                   children: [ | ||||||
|  |                     Text('copyKeyHint'.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(token), | ||||||
|  |                     ), | ||||||
|  |                     const SizedBox(height: 20), | ||||||
|  |                     FilledButton.icon( | ||||||
|  |                       onPressed: () { | ||||||
|  |                         Clipboard.setData(ClipboardData(text: token)); | ||||||
|  |                       }, | ||||||
|  |                       icon: const Icon(Symbols.copy_all), | ||||||
|  |                       label: Text('copy'.tr()), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |       ).whenComplete(() { | ||||||
|  |         ref.invalidate(botKeysProvider(publisherName, projectId, botId)); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void createKey() { | ||||||
|  |       keyNameController.clear(); | ||||||
|  |       showModalBottomSheet( | ||||||
|  |         context: context, | ||||||
|  |         isScrollControlled: true, | ||||||
|  |         builder: | ||||||
|  |             (context) => SheetScaffold( | ||||||
|  |               titleText: 'newBotKey'.tr(), | ||||||
|  |               child: Padding( | ||||||
|  |                 padding: const EdgeInsets.all(20.0), | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                   mainAxisSize: MainAxisSize.min, | ||||||
|  |                   children: [ | ||||||
|  |                     TextFormField( | ||||||
|  |                       controller: keyNameController, | ||||||
|  |                       decoration: InputDecoration(labelText: 'keyName'.tr()), | ||||||
|  |                       autofocus: true, | ||||||
|  |                     ), | ||||||
|  |                     const SizedBox(height: 20), | ||||||
|  |                     FilledButton.icon( | ||||||
|  |                       onPressed: () async { | ||||||
|  |                         if (keyNameController.text.isEmpty) return; | ||||||
|  |                         final keyName = keyNameController.text; | ||||||
|  |                         Navigator.pop(context); // Close the sheet | ||||||
|  |                         try { | ||||||
|  |                           final client = ref.read(apiClientProvider); | ||||||
|  |                           final resp = await client.post( | ||||||
|  |                             '/develop/developers/$publisherName/projects/$projectId/bots/$botId/keys', | ||||||
|  |                             data: {'label': keyName}, | ||||||
|  |                           ); | ||||||
|  |                           final newApiKey = SnAccountApiKey.fromJson(resp.data); | ||||||
|  |                           showNewKeySheet(newApiKey); | ||||||
|  |                         } catch (e) { | ||||||
|  |                           showErrorAlert(e.toString()); | ||||||
|  |                         } | ||||||
|  |                       }, | ||||||
|  |                       icon: const Icon(Symbols.add), | ||||||
|  |                       label: Text('create'.tr()), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void rotateKey(String keyId) { | ||||||
|  |       showConfirmAlert('rotateBotKeyHint'.tr(), 'rotateBotKey'.tr()).then(( | ||||||
|  |         confirm, | ||||||
|  |       ) async { | ||||||
|  |         if (confirm) { | ||||||
|  |           try { | ||||||
|  |             if (context.mounted) showLoadingModal(context); | ||||||
|  |             final client = ref.read(apiClientProvider); | ||||||
|  |             final resp = await client.post( | ||||||
|  |               '/develop/developers/$publisherName/projects/$projectId/bots/$botId/keys/$keyId/rotate', | ||||||
|  |             ); | ||||||
|  |             final rotatedApiKey = SnAccountApiKey.fromJson(resp.data); | ||||||
|  |             showNewKeySheet(rotatedApiKey); | ||||||
|  |           } catch (err) { | ||||||
|  |             showErrorAlert(err.toString()); | ||||||
|  |           } finally { | ||||||
|  |             if (context.mounted) hideLoadingModal(context); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void revokeKey(String keyId) { | ||||||
|  |       showConfirmAlert('revokeBotKeyHint'.tr(), 'revokeBotKey'.tr()).then(( | ||||||
|  |         confirm, | ||||||
|  |       ) { | ||||||
|  |         if (confirm) { | ||||||
|  |           final client = ref.read(apiClientProvider); | ||||||
|  |           client | ||||||
|  |               .delete( | ||||||
|  |                 '/develop/developers/$publisherName/projects/$projectId/bots/$botId/keys/$keyId', | ||||||
|  |               ) | ||||||
|  |               .then((_) { | ||||||
|  |                 ref.invalidate( | ||||||
|  |                   botKeysProvider(publisherName, projectId, botId), | ||||||
|  |                 ); | ||||||
|  |               }) | ||||||
|  |               .catchError((err) { | ||||||
|  |                 showErrorAlert(err.toString()); | ||||||
|  |               }); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return keys.when( | ||||||
|  |       data: (data) { | ||||||
|  |         return Column( | ||||||
|  |           children: [ | ||||||
|  |             ListTile( | ||||||
|  |               leading: const Icon(Symbols.add), | ||||||
|  |               title: Text('newBotKey'.tr()), | ||||||
|  |               trailing: const Icon(Symbols.chevron_right), | ||||||
|  |               onTap: createKey, | ||||||
|  |             ), | ||||||
|  |             const Divider(height: 1), | ||||||
|  |             Expanded( | ||||||
|  |               child: | ||||||
|  |                   data.isEmpty | ||||||
|  |                       ? Center(child: Text('noBotKeys'.tr())) | ||||||
|  |                       : RefreshIndicator( | ||||||
|  |                         onRefresh: | ||||||
|  |                             () => ref.refresh( | ||||||
|  |                               botKeysProvider( | ||||||
|  |                                 publisherName, | ||||||
|  |                                 projectId, | ||||||
|  |                                 botId, | ||||||
|  |                               ).future, | ||||||
|  |                             ), | ||||||
|  |                         child: ListView.builder( | ||||||
|  |                           padding: EdgeInsets.zero, | ||||||
|  |                           itemCount: data.length, | ||||||
|  |                           itemBuilder: (context, index) { | ||||||
|  |                             final apiKey = data[index]; | ||||||
|  |                             return ListTile( | ||||||
|  |                               title: Text(apiKey.label), | ||||||
|  |                               subtitle: Text(apiKey.createdAt.formatSystem()), | ||||||
|  |                               contentPadding: EdgeInsets.only( | ||||||
|  |                                 left: 16, | ||||||
|  |                                 right: 12, | ||||||
|  |                               ), | ||||||
|  |                               trailing: PopupMenuButton( | ||||||
|  |                                 itemBuilder: | ||||||
|  |                                     (context) => [ | ||||||
|  |                                       PopupMenuItem( | ||||||
|  |                                         value: 'rotate', | ||||||
|  |                                         child: Row( | ||||||
|  |                                           children: [ | ||||||
|  |                                             const Icon(Symbols.refresh), | ||||||
|  |                                             const Gap(12), | ||||||
|  |                                             Text('rotateKey'.tr()), | ||||||
|  |                                           ], | ||||||
|  |                                         ), | ||||||
|  |                                       ), | ||||||
|  |                                       PopupMenuItem( | ||||||
|  |                                         value: 'revoke', | ||||||
|  |                                         child: Row( | ||||||
|  |                                           children: [ | ||||||
|  |                                             const Icon( | ||||||
|  |                                               Symbols.delete, | ||||||
|  |                                               color: Colors.red, | ||||||
|  |                                             ), | ||||||
|  |                                             const Gap(12), | ||||||
|  |                                             Text( | ||||||
|  |                                               'revoke'.tr(), | ||||||
|  |                                               style: TextStyle( | ||||||
|  |                                                 color: Colors.red, | ||||||
|  |                                               ), | ||||||
|  |                                             ), | ||||||
|  |                                           ], | ||||||
|  |                                         ), | ||||||
|  |                                       ), | ||||||
|  |                                     ], | ||||||
|  |                                 onSelected: (value) { | ||||||
|  |                                   if (value == 'rotate') { | ||||||
|  |                                     rotateKey(apiKey.id); | ||||||
|  |                                   } else if (value == 'revoke') { | ||||||
|  |                                     revokeKey(apiKey.id); | ||||||
|  |                                   } | ||||||
|  |                                 }, | ||||||
|  |                               ), | ||||||
|  |                             ); | ||||||
|  |                           }, | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|  |       loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |       error: | ||||||
|  |           (err, stack) => ResponseErrorWidget( | ||||||
|  |             error: err, | ||||||
|  |             onRetry: | ||||||
|  |                 () => ref.invalidate( | ||||||
|  |                   botKeysProvider(publisherName, projectId, botId), | ||||||
|  |                 ), | ||||||
|  |           ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										172
									
								
								lib/screens/developers/bot_keys.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								lib/screens/developers/bot_keys.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'bot_keys.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // RiverpodGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | String _$botKeysHash() => r'f7d1121833dc3da0cbd84b6171c2b2539edeb785'; | ||||||
|  |  | ||||||
|  | /// 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 [botKeys]. | ||||||
|  | @ProviderFor(botKeys) | ||||||
|  | const botKeysProvider = BotKeysFamily(); | ||||||
|  |  | ||||||
|  | /// See also [botKeys]. | ||||||
|  | class BotKeysFamily extends Family<AsyncValue<List<SnAccountApiKey>>> { | ||||||
|  |   /// See also [botKeys]. | ||||||
|  |   const BotKeysFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [botKeys]. | ||||||
|  |   BotKeysProvider call(String publisherName, String projectId, String botId) { | ||||||
|  |     return BotKeysProvider(publisherName, projectId, botId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   BotKeysProvider getProviderOverride(covariant BotKeysProvider provider) { | ||||||
|  |     return call(provider.publisherName, provider.projectId, provider.botId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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'botKeysProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [botKeys]. | ||||||
|  | class BotKeysProvider extends AutoDisposeFutureProvider<List<SnAccountApiKey>> { | ||||||
|  |   /// See also [botKeys]. | ||||||
|  |   BotKeysProvider(String publisherName, String projectId, String botId) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => botKeys(ref as BotKeysRef, publisherName, projectId, botId), | ||||||
|  |         from: botKeysProvider, | ||||||
|  |         name: r'botKeysProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$botKeysHash, | ||||||
|  |         dependencies: BotKeysFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: BotKeysFamily._allTransitiveDependencies, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         botId: botId, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   BotKeysProvider._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.botId, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String botId; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<List<SnAccountApiKey>> Function(BotKeysRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: BotKeysProvider._internal( | ||||||
|  |         (ref) => create(ref as BotKeysRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         botId: botId, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<List<SnAccountApiKey>> createElement() { | ||||||
|  |     return _BotKeysProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is BotKeysProvider && | ||||||
|  |         other.publisherName == publisherName && | ||||||
|  |         other.projectId == projectId && | ||||||
|  |         other.botId == botId; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @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, botId.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin BotKeysRef on AutoDisposeFutureProviderRef<List<SnAccountApiKey>> { | ||||||
|  |   /// The parameter `publisherName` of this provider. | ||||||
|  |   String get publisherName; | ||||||
|  |  | ||||||
|  |   /// The parameter `projectId` of this provider. | ||||||
|  |   String get projectId; | ||||||
|  |  | ||||||
|  |   /// The parameter `botId` of this provider. | ||||||
|  |   String get botId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _BotKeysProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<List<SnAccountApiKey>> | ||||||
|  |     with BotKeysRef { | ||||||
|  |   _BotKeysProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get publisherName => (origin as BotKeysProvider).publisherName; | ||||||
|  |   @override | ||||||
|  |   String get projectId => (origin as BotKeysProvider).projectId; | ||||||
|  |   @override | ||||||
|  |   String get botId => (origin as BotKeysProvider).botId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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 | ||||||
							
								
								
									
										168
									
								
								lib/screens/developers/bots.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								lib/screens/developers/bots.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,168 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/bot.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/widgets/alert.dart'; | ||||||
|  | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
|  | import 'package:island/widgets/response.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  | import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||||
|  |  | ||||||
|  | part 'bots.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<List<Bot>> bots(Ref ref, String publisherName, String projectId) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await client.get( | ||||||
|  |     '/develop/developers/$publisherName/projects/$projectId/bots', | ||||||
|  |   ); | ||||||
|  |   return (resp.data as List).map((e) => Bot.fromJson(e)).cast<Bot>().toList(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class BotsScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   const BotsScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final botsList = ref.watch(botsProvider(publisherName, projectId)); | ||||||
|  |  | ||||||
|  |     return botsList.when( | ||||||
|  |       data: (data) { | ||||||
|  |         if (data.isEmpty) { | ||||||
|  |           return Center( | ||||||
|  |             child: Column( | ||||||
|  |               mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |               children: [ | ||||||
|  |                 Text('noBots').tr(), | ||||||
|  |                 const SizedBox(height: 16), | ||||||
|  |                 ElevatedButton.icon( | ||||||
|  |                   onPressed: () { | ||||||
|  |                     context.pushNamed( | ||||||
|  |                       'developerBotNew', | ||||||
|  |                       pathParameters: { | ||||||
|  |                         'name': publisherName, | ||||||
|  |                         'projectId': projectId, | ||||||
|  |                       }, | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|  |                   icon: const Icon(Symbols.add), | ||||||
|  |                   label: Text('createBot').tr(), | ||||||
|  |                 ), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |         return ExtendedRefreshIndicator( | ||||||
|  |           onRefresh: | ||||||
|  |               () => ref.refresh(botsProvider(publisherName, projectId).future), | ||||||
|  |           child: ListView.builder( | ||||||
|  |             padding: const EdgeInsets.only(top: 4), | ||||||
|  |             itemCount: data.length, | ||||||
|  |             itemBuilder: (context, index) { | ||||||
|  |               final bot = data[index]; | ||||||
|  |               return Card( | ||||||
|  |                 margin: const EdgeInsets.all(8.0), | ||||||
|  |                 child: ListTile( | ||||||
|  |                   shape: const RoundedRectangleBorder( | ||||||
|  |                     borderRadius: BorderRadius.all(Radius.circular(8.0)), | ||||||
|  |                   ), | ||||||
|  |                   leading: CircleAvatar( | ||||||
|  |                     child: | ||||||
|  |                         bot.account.profile.picture != null | ||||||
|  |                             ? ProfilePictureWidget( | ||||||
|  |                               file: bot.account.profile.picture!, | ||||||
|  |                             ) | ||||||
|  |                             : const Icon(Symbols.smart_toy), | ||||||
|  |                   ), | ||||||
|  |                   title: Text(bot.account.nick), | ||||||
|  |                   subtitle: Text(bot.account.name), | ||||||
|  |                   trailing: PopupMenuButton( | ||||||
|  |                     itemBuilder: | ||||||
|  |                         (context) => [ | ||||||
|  |                           PopupMenuItem( | ||||||
|  |                             value: 'edit', | ||||||
|  |                             child: Row( | ||||||
|  |                               children: [ | ||||||
|  |                                 const Icon(Symbols.edit), | ||||||
|  |                                 const SizedBox(width: 12), | ||||||
|  |                                 Text('edit').tr(), | ||||||
|  |                               ], | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                           PopupMenuItem( | ||||||
|  |                             value: 'delete', | ||||||
|  |                             child: Row( | ||||||
|  |                               children: [ | ||||||
|  |                                 const Icon(Symbols.delete, color: Colors.red), | ||||||
|  |                                 const SizedBox(width: 12), | ||||||
|  |                                 Text( | ||||||
|  |                                   'delete', | ||||||
|  |                                   style: TextStyle(color: Colors.red), | ||||||
|  |                                 ).tr(), | ||||||
|  |                               ], | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                     onSelected: (value) { | ||||||
|  |                       if (value == 'edit') { | ||||||
|  |                         context.pushNamed( | ||||||
|  |                           'developerBotEdit', | ||||||
|  |                           pathParameters: { | ||||||
|  |                             'name': publisherName, | ||||||
|  |                             'projectId': projectId, | ||||||
|  |                             'id': bot.id, | ||||||
|  |                           }, | ||||||
|  |                         ); | ||||||
|  |                       } else if (value == 'delete') { | ||||||
|  |                         showConfirmAlert( | ||||||
|  |                           'deleteBotHint'.tr(), | ||||||
|  |                           'deleteBot'.tr(), | ||||||
|  |                         ).then((confirm) { | ||||||
|  |                           if (confirm) { | ||||||
|  |                             final client = ref.read(apiClientProvider); | ||||||
|  |                             client.delete( | ||||||
|  |                               '/develop/developers/$publisherName/projects/$projectId/bots/${bot.id}', | ||||||
|  |                             ); | ||||||
|  |                             ref.invalidate( | ||||||
|  |                               botsProvider(publisherName, projectId), | ||||||
|  |                             ); | ||||||
|  |                           } | ||||||
|  |                         }); | ||||||
|  |                       } | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                   onTap: () { | ||||||
|  |                     context.pushNamed( | ||||||
|  |                       'developerBotDetail', | ||||||
|  |                       pathParameters: { | ||||||
|  |                         'name': publisherName, | ||||||
|  |                         'projectId': projectId, | ||||||
|  |                         'botId': bot.id, | ||||||
|  |                       }, | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |               ); | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|  |       loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |       error: | ||||||
|  |           (err, stack) => ResponseErrorWidget( | ||||||
|  |             error: err, | ||||||
|  |             onRetry: | ||||||
|  |                 () => ref.invalidate(botsProvider(publisherName, projectId)), | ||||||
|  |           ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										156
									
								
								lib/screens/developers/bots.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								lib/screens/developers/bots.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'bots.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // RiverpodGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | String _$botsHash() => r'15cefd5781350eb68208a342e85fcb0b9e0e3269'; | ||||||
|  |  | ||||||
|  | /// 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 [bots]. | ||||||
|  | @ProviderFor(bots) | ||||||
|  | const botsProvider = BotsFamily(); | ||||||
|  |  | ||||||
|  | /// See also [bots]. | ||||||
|  | class BotsFamily extends Family<AsyncValue<List<Bot>>> { | ||||||
|  |   /// See also [bots]. | ||||||
|  |   const BotsFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [bots]. | ||||||
|  |   BotsProvider call(String publisherName, String projectId) { | ||||||
|  |     return BotsProvider(publisherName, projectId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   BotsProvider getProviderOverride(covariant BotsProvider provider) { | ||||||
|  |     return call(provider.publisherName, provider.projectId); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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'botsProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [bots]. | ||||||
|  | class BotsProvider extends AutoDisposeFutureProvider<List<Bot>> { | ||||||
|  |   /// See also [bots]. | ||||||
|  |   BotsProvider(String publisherName, String projectId) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => bots(ref as BotsRef, publisherName, projectId), | ||||||
|  |         from: botsProvider, | ||||||
|  |         name: r'botsProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') ? null : _$botsHash, | ||||||
|  |         dependencies: BotsFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: BotsFamily._allTransitiveDependencies, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   BotsProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith(FutureOr<List<Bot>> Function(BotsRef provider) create) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: BotsProvider._internal( | ||||||
|  |         (ref) => create(ref as BotsRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<List<Bot>> createElement() { | ||||||
|  |     return _BotsProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is BotsProvider && | ||||||
|  |         other.publisherName == publisherName && | ||||||
|  |         other.projectId == projectId; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, publisherName.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, projectId.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin BotsRef on AutoDisposeFutureProviderRef<List<Bot>> { | ||||||
|  |   /// The parameter `publisherName` of this provider. | ||||||
|  |   String get publisherName; | ||||||
|  |  | ||||||
|  |   /// The parameter `projectId` of this provider. | ||||||
|  |   String get projectId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _BotsProviderElement extends AutoDisposeFutureProviderElement<List<Bot>> | ||||||
|  |     with BotsRef { | ||||||
|  |   _BotsProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get publisherName => (origin as BotsProvider).publisherName; | ||||||
|  |   @override | ||||||
|  |   String get projectId => (origin as BotsProvider).projectId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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 | ||||||
| @@ -22,21 +22,37 @@ import 'package:island/widgets/content/sheet.dart'; | |||||||
| part 'edit_app.g.dart'; | part 'edit_app.g.dart'; | ||||||
|  |  | ||||||
| @riverpod | @riverpod | ||||||
| Future<CustomApp?> customApp(Ref ref, String publisherName, String id) async { | Future<CustomApp?> customApp( | ||||||
|  |   Ref ref, | ||||||
|  |   String publisherName, | ||||||
|  |   String projectId, | ||||||
|  |   String id, | ||||||
|  | ) async { | ||||||
|   final client = ref.watch(apiClientProvider); |   final client = ref.watch(apiClientProvider); | ||||||
|   final resp = await client.get('/develop/developers/$publisherName/apps/$id'); |   final resp = await client.get( | ||||||
|  |     '/develop/developers/$publisherName/projects/$projectId/apps/$id', | ||||||
|  |   ); | ||||||
|   return CustomApp.fromJson(resp.data); |   return CustomApp.fromJson(resp.data); | ||||||
| } | } | ||||||
|  |  | ||||||
| class EditAppScreen extends HookConsumerWidget { | class EditAppScreen extends HookConsumerWidget { | ||||||
|   final String publisherName; |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|   final String? id; |   final String? id; | ||||||
|   const EditAppScreen({super.key, required this.publisherName, this.id}); |   const EditAppScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     this.id, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context, WidgetRef ref) { |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|     final isNew = id == null; |     final isNew = id == null; | ||||||
|     final app = isNew ? null : ref.watch(customAppProvider(publisherName, id!)); |     final app = | ||||||
|  |         isNew | ||||||
|  |             ? null | ||||||
|  |             : ref.watch(customAppProvider(publisherName, projectId, id!)); | ||||||
|  |  | ||||||
|     final formKey = useMemoized(() => GlobalKey<FormState>()); |     final formKey = useMemoized(() => GlobalKey<FormState>()); | ||||||
|  |  | ||||||
| @@ -281,18 +297,26 @@ class EditAppScreen extends HookConsumerWidget { | |||||||
|                 } |                 } | ||||||
|                 : null, |                 : null, | ||||||
|       }; |       }; | ||||||
|       if (isNew) { |       try { | ||||||
|         await client.post( |         showLoadingModal(context); | ||||||
|           '/develop/developers/$publisherName/apps', |         if (isNew) { | ||||||
|           data: data, |           await client.post( | ||||||
|         ); |             '/develop/developers/$publisherName/projects/$projectId/apps', | ||||||
|       } else { |             data: data, | ||||||
|         await client.patch( |           ); | ||||||
|           '/develop/developers/$publisherName/apps/$id', |         } else { | ||||||
|           data: data, |           await client.patch( | ||||||
|         ); |             '/develop/developers/$publisherName/projects/$projectId/apps/$id', | ||||||
|  |             data: data, | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       } catch (err) { | ||||||
|  |         showErrorAlert(err); | ||||||
|  |         return; | ||||||
|  |       } finally { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|       } |       } | ||||||
|       ref.invalidate(customAppsProvider(publisherName)); |       ref.invalidate(customAppsProvider(publisherName, projectId)); | ||||||
|       if (context.mounted) { |       if (context.mounted) { | ||||||
|         Navigator.pop(context); |         Navigator.pop(context); | ||||||
|       } |       } | ||||||
| @@ -309,7 +333,9 @@ class EditAppScreen extends HookConsumerWidget { | |||||||
|               ? ResponseErrorWidget( |               ? ResponseErrorWidget( | ||||||
|                 error: app!.error, |                 error: app!.error, | ||||||
|                 onRetry: |                 onRetry: | ||||||
|                     () => ref.invalidate(customAppProvider(publisherName, id!)), |                     () => ref.invalidate( | ||||||
|  |                       customAppProvider(publisherName, projectId, id!), | ||||||
|  |                     ), | ||||||
|               ) |               ) | ||||||
|               : SingleChildScrollView( |               : SingleChildScrollView( | ||||||
|                 child: Column( |                 child: Column( | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ part of 'edit_app.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$customAppHash() => r'42ad937b8439c793e3c5c35568bb5fa4da017df3'; | String _$customAppHash() => r'8e1b38f3dc9b04fad362ee1141fcbfc53f008c09'; | ||||||
|  |  | ||||||
| /// Copied from Dart SDK | /// Copied from Dart SDK | ||||||
| class _SystemHash { | class _SystemHash { | ||||||
| @@ -39,13 +39,13 @@ class CustomAppFamily extends Family<AsyncValue<CustomApp?>> { | |||||||
|   const CustomAppFamily(); |   const CustomAppFamily(); | ||||||
|  |  | ||||||
|   /// See also [customApp]. |   /// See also [customApp]. | ||||||
|   CustomAppProvider call(String publisherName, String id) { |   CustomAppProvider call(String publisherName, String projectId, String id) { | ||||||
|     return CustomAppProvider(publisherName, id); |     return CustomAppProvider(publisherName, projectId, id); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   CustomAppProvider getProviderOverride(covariant CustomAppProvider provider) { |   CustomAppProvider getProviderOverride(covariant CustomAppProvider provider) { | ||||||
|     return call(provider.publisherName, provider.id); |     return call(provider.publisherName, provider.projectId, provider.id); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static const Iterable<ProviderOrFamily>? _dependencies = null; |   static const Iterable<ProviderOrFamily>? _dependencies = null; | ||||||
| @@ -66,9 +66,9 @@ class CustomAppFamily extends Family<AsyncValue<CustomApp?>> { | |||||||
| /// See also [customApp]. | /// See also [customApp]. | ||||||
| class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | ||||||
|   /// See also [customApp]. |   /// See also [customApp]. | ||||||
|   CustomAppProvider(String publisherName, String id) |   CustomAppProvider(String publisherName, String projectId, String id) | ||||||
|     : this._internal( |     : this._internal( | ||||||
|         (ref) => customApp(ref as CustomAppRef, publisherName, id), |         (ref) => customApp(ref as CustomAppRef, publisherName, projectId, id), | ||||||
|         from: customAppProvider, |         from: customAppProvider, | ||||||
|         name: r'customAppProvider', |         name: r'customAppProvider', | ||||||
|         debugGetCreateSourceHash: |         debugGetCreateSourceHash: | ||||||
| @@ -78,6 +78,7 @@ class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | |||||||
|         dependencies: CustomAppFamily._dependencies, |         dependencies: CustomAppFamily._dependencies, | ||||||
|         allTransitiveDependencies: CustomAppFamily._allTransitiveDependencies, |         allTransitiveDependencies: CustomAppFamily._allTransitiveDependencies, | ||||||
|         publisherName: publisherName, |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|         id: id, |         id: id, | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
| @@ -89,10 +90,12 @@ class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | |||||||
|     required super.debugGetCreateSourceHash, |     required super.debugGetCreateSourceHash, | ||||||
|     required super.from, |     required super.from, | ||||||
|     required this.publisherName, |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|     required this.id, |     required this.id, | ||||||
|   }) : super.internal(); |   }) : super.internal(); | ||||||
|  |  | ||||||
|   final String publisherName; |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|   final String id; |   final String id; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -109,6 +112,7 @@ class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | |||||||
|         allTransitiveDependencies: null, |         allTransitiveDependencies: null, | ||||||
|         debugGetCreateSourceHash: null, |         debugGetCreateSourceHash: null, | ||||||
|         publisherName: publisherName, |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|         id: id, |         id: id, | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
| @@ -123,6 +127,7 @@ class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | |||||||
|   bool operator ==(Object other) { |   bool operator ==(Object other) { | ||||||
|     return other is CustomAppProvider && |     return other is CustomAppProvider && | ||||||
|         other.publisherName == publisherName && |         other.publisherName == publisherName && | ||||||
|  |         other.projectId == projectId && | ||||||
|         other.id == id; |         other.id == id; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -130,6 +135,7 @@ class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp?> { | |||||||
|   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); | ||||||
|     hash = _SystemHash.combine(hash, id.hashCode); |     hash = _SystemHash.combine(hash, id.hashCode); | ||||||
|  |  | ||||||
|     return _SystemHash.finish(hash); |     return _SystemHash.finish(hash); | ||||||
| @@ -142,6 +148,9 @@ mixin CustomAppRef on AutoDisposeFutureProviderRef<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; | ||||||
|  |  | ||||||
|   /// The parameter `id` of this provider. |   /// The parameter `id` of this provider. | ||||||
|   String get id; |   String get id; | ||||||
| } | } | ||||||
| @@ -154,6 +163,8 @@ class _CustomAppProviderElement | |||||||
|   @override |   @override | ||||||
|   String get publisherName => (origin as CustomAppProvider).publisherName; |   String get publisherName => (origin as CustomAppProvider).publisherName; | ||||||
|   @override |   @override | ||||||
|  |   String get projectId => (origin as CustomAppProvider).projectId; | ||||||
|  |   @override | ||||||
|   String get id => (origin as CustomAppProvider).id; |   String get id => (origin as CustomAppProvider).id; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										425
									
								
								lib/screens/developers/edit_bot.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										425
									
								
								lib/screens/developers/edit_bot.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,425 @@ | |||||||
|  | import 'package:croppy/croppy.dart' hide cropImage; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:image_picker/image_picker.dart'; | ||||||
|  | import 'package:island/models/bot.dart'; | ||||||
|  | import 'package:island/models/file.dart'; | ||||||
|  | import 'package:island/pods/config.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/services/file.dart'; | ||||||
|  | import 'package:island/widgets/alert.dart'; | ||||||
|  | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|  | import 'package:island/widgets/content/cloud_files.dart'; | ||||||
|  | import 'package:island/widgets/response.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
|  | part 'edit_bot.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<Bot?> bot( | ||||||
|  |   Ref ref, | ||||||
|  |   String publisherName, | ||||||
|  |   String projectId, | ||||||
|  |   String id, | ||||||
|  | ) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await client.get( | ||||||
|  |     '/develop/developers/$publisherName/projects/$projectId/bots/$id', | ||||||
|  |   ); | ||||||
|  |   return Bot.fromJson(resp.data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class EditBotScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String? id; | ||||||
|  |   const EditBotScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |     this.id, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final isNew = id == null; | ||||||
|  |     final botData = | ||||||
|  |         isNew ? null : ref.watch(botProvider(publisherName, projectId, id!)); | ||||||
|  |  | ||||||
|  |     final formKey = useMemoized(() => GlobalKey<FormState>()); | ||||||
|  |     final submitting = useState(false); | ||||||
|  |  | ||||||
|  |     final nameController = useTextEditingController(); | ||||||
|  |     final nickController = useTextEditingController(); | ||||||
|  |     final slugController = useTextEditingController(); | ||||||
|  |     final picture = useState<SnCloudFile?>(null); | ||||||
|  |  | ||||||
|  |     final firstNameController = useTextEditingController(); | ||||||
|  |     final middleNameController = useTextEditingController(); | ||||||
|  |     final lastNameController = useTextEditingController(); | ||||||
|  |     final genderController = useTextEditingController(); | ||||||
|  |     final pronounsController = useTextEditingController(); | ||||||
|  |     final locationController = useTextEditingController(); | ||||||
|  |     final timeZoneController = useTextEditingController(); | ||||||
|  |     final bioController = useTextEditingController(); | ||||||
|  |     final birthday = useState<DateTime?>(null); | ||||||
|  |     final background = useState<SnCloudFile?>(null); | ||||||
|  |  | ||||||
|  |     useEffect(() { | ||||||
|  |       if (botData?.value != null) { | ||||||
|  |         nameController.text = botData!.value!.account.name; | ||||||
|  |         nickController.text = botData.value!.account.nick; | ||||||
|  |         slugController.text = botData.value!.slug; | ||||||
|  |         picture.value = botData.value!.account.profile.picture; | ||||||
|  |         background.value = botData.value!.account.profile.background; | ||||||
|  |  | ||||||
|  |         // Populate from botData.value.account.profile | ||||||
|  |         firstNameController.text = botData.value!.account.profile.firstName; | ||||||
|  |         middleNameController.text = botData.value!.account.profile.middleName; | ||||||
|  |         lastNameController.text = botData.value!.account.profile.lastName; | ||||||
|  |         genderController.text = botData.value!.account.profile.gender; | ||||||
|  |         pronounsController.text = botData.value!.account.profile.pronouns; | ||||||
|  |         locationController.text = botData.value!.account.profile.location; | ||||||
|  |         timeZoneController.text = botData.value!.account.profile.timeZone; | ||||||
|  |         bioController.text = botData.value!.account.profile.bio; | ||||||
|  |         birthday.value = botData.value!.account.profile.birthday?.toLocal(); | ||||||
|  |       } | ||||||
|  |       return null; | ||||||
|  |     }, [botData]); | ||||||
|  |  | ||||||
|  |     void setPicture(String position) async { | ||||||
|  |       showLoadingModal(context); | ||||||
|  |       var result = await ref | ||||||
|  |           .read(imagePickerProvider) | ||||||
|  |           .pickImage(source: ImageSource.gallery); | ||||||
|  |       if (result == null) { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       if (!context.mounted) return; | ||||||
|  |       hideLoadingModal(context); | ||||||
|  |  | ||||||
|  |       result = await cropImage( | ||||||
|  |         context, | ||||||
|  |         image: result, | ||||||
|  |         allowedAspectRatios: [ | ||||||
|  |           if (position == 'background') | ||||||
|  |             const CropAspectRatio(height: 7, width: 16) | ||||||
|  |           else | ||||||
|  |             const CropAspectRatio(height: 1, width: 1), | ||||||
|  |         ], | ||||||
|  |       ); | ||||||
|  |       if (result == null) { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       if (!context.mounted) return; | ||||||
|  |       showLoadingModal(context); | ||||||
|  |  | ||||||
|  |       submitting.value = true; | ||||||
|  |       try { | ||||||
|  |         final baseUrl = ref.watch(serverUrlProvider); | ||||||
|  |         final token = await getToken(ref.watch(tokenProvider)); | ||||||
|  |         if (token == null) throw ArgumentError('Token is null'); | ||||||
|  |         final cloudFile = | ||||||
|  |             await putMediaToCloud( | ||||||
|  |               fileData: UniversalFile( | ||||||
|  |                 data: result, | ||||||
|  |                 type: UniversalFileType.image, | ||||||
|  |               ), | ||||||
|  |               atk: token, | ||||||
|  |               baseUrl: baseUrl, | ||||||
|  |               filename: result.name, | ||||||
|  |               mimetype: result.mimeType ?? 'image/jpeg', | ||||||
|  |             ).future; | ||||||
|  |         if (cloudFile == null) { | ||||||
|  |           throw ArgumentError('Failed to upload the file...'); | ||||||
|  |         } | ||||||
|  |         switch (position) { | ||||||
|  |           case 'picture': | ||||||
|  |             picture.value = cloudFile; | ||||||
|  |           case 'background': | ||||||
|  |             background.value = cloudFile; | ||||||
|  |         } | ||||||
|  |       } catch (err) { | ||||||
|  |         showErrorAlert(err); | ||||||
|  |       } finally { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |         submitting.value = false; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void performAction() async { | ||||||
|  |       final client = ref.read(apiClientProvider); | ||||||
|  |       final data = { | ||||||
|  |         'name': nameController.text, | ||||||
|  |         'nick': nickController.text, | ||||||
|  |         'slug': slugController.text, | ||||||
|  |         'picture_id': picture.value?.id, | ||||||
|  |         'background_id': background.value?.id, | ||||||
|  |         'first_name': firstNameController.text, | ||||||
|  |         'middle_name': middleNameController.text, | ||||||
|  |         'last_name': lastNameController.text, | ||||||
|  |         'gender': genderController.text, | ||||||
|  |         'pronouns': pronounsController.text, | ||||||
|  |         'location': locationController.text, | ||||||
|  |         'time_zone': timeZoneController.text, | ||||||
|  |         'bio': bioController.text, | ||||||
|  |         'birthday': birthday.value?.toUtc().toIso8601String(), | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       try { | ||||||
|  |         showLoadingModal(context); | ||||||
|  |         if (isNew) { | ||||||
|  |           await client.post( | ||||||
|  |             '/develop/developers/$publisherName/projects/$projectId/bots', | ||||||
|  |             data: data, | ||||||
|  |           ); | ||||||
|  |         } else { | ||||||
|  |           await client.patch( | ||||||
|  |             '/develop/developers/$publisherName/projects/$projectId/bots/$id', | ||||||
|  |             data: data, | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (context.mounted) { | ||||||
|  |           context.pop(); | ||||||
|  |         } | ||||||
|  |       } catch (err) { | ||||||
|  |         showErrorAlert(err); | ||||||
|  |       } finally { | ||||||
|  |         if (context.mounted) hideLoadingModal(context); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar(title: Text(isNew ? 'createBot'.tr() : 'editBot'.tr())), | ||||||
|  |       body: | ||||||
|  |           botData == null && !isNew | ||||||
|  |               ? const Center(child: CircularProgressIndicator()) | ||||||
|  |               : botData?.hasError == true && !isNew | ||||||
|  |               ? ResponseErrorWidget( | ||||||
|  |                 error: botData!.error, | ||||||
|  |                 onRetry: | ||||||
|  |                     () => ref.invalidate( | ||||||
|  |                       botProvider(publisherName, projectId, id!), | ||||||
|  |                     ), | ||||||
|  |               ) | ||||||
|  |               : SingleChildScrollView( | ||||||
|  |                 child: Column( | ||||||
|  |                   children: [ | ||||||
|  |                     AspectRatio( | ||||||
|  |                       aspectRatio: 16 / 7, | ||||||
|  |                       child: Stack( | ||||||
|  |                         clipBehavior: Clip.none, | ||||||
|  |                         fit: StackFit.expand, | ||||||
|  |                         children: [ | ||||||
|  |                           GestureDetector( | ||||||
|  |                             child: Container( | ||||||
|  |                               color: | ||||||
|  |                                   Theme.of( | ||||||
|  |                                     context, | ||||||
|  |                                   ).colorScheme.surfaceContainerHigh, | ||||||
|  |                               child: | ||||||
|  |                                   background.value != null | ||||||
|  |                                       ? CloudFileWidget( | ||||||
|  |                                         item: background.value!, | ||||||
|  |                                         fit: BoxFit.cover, | ||||||
|  |                                       ) | ||||||
|  |                                       : const SizedBox.shrink(), | ||||||
|  |                             ), | ||||||
|  |                             onTap: () { | ||||||
|  |                               setPicture('background'); | ||||||
|  |                             }, | ||||||
|  |                           ), | ||||||
|  |                           Positioned( | ||||||
|  |                             left: 20, | ||||||
|  |                             bottom: -32, | ||||||
|  |                             child: GestureDetector( | ||||||
|  |                               child: ProfilePictureWidget( | ||||||
|  |                                 fileId: picture.value?.id, | ||||||
|  |                                 radius: 40, | ||||||
|  |                                 fallbackIcon: Symbols.smart_toy, | ||||||
|  |                               ), | ||||||
|  |                               onTap: () { | ||||||
|  |                                 setPicture('picture'); | ||||||
|  |                               }, | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ).padding(bottom: 32), | ||||||
|  |                     Form( | ||||||
|  |                       key: formKey, | ||||||
|  |                       child: Column( | ||||||
|  |                         children: [ | ||||||
|  |                           TextFormField( | ||||||
|  |                             controller: nameController, | ||||||
|  |                             decoration: InputDecoration(labelText: 'name'.tr()), | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           TextFormField( | ||||||
|  |                             controller: nickController, | ||||||
|  |                             decoration: InputDecoration( | ||||||
|  |                               labelText: 'nickname'.tr(), | ||||||
|  |                               alignLabelWithHint: true, | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           TextFormField( | ||||||
|  |                             controller: slugController, | ||||||
|  |                             decoration: InputDecoration( | ||||||
|  |                               labelText: 'slug'.tr(), | ||||||
|  |                               helperText: 'slugHint'.tr(), | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           TextFormField( | ||||||
|  |                             controller: bioController, | ||||||
|  |                             decoration: InputDecoration( | ||||||
|  |                               labelText: 'bio'.tr(), | ||||||
|  |                               alignLabelWithHint: true, | ||||||
|  |                             ), | ||||||
|  |                             maxLines: 3, | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           Row( | ||||||
|  |                             spacing: 16, | ||||||
|  |                             children: [ | ||||||
|  |                               Expanded( | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   controller: firstNameController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'firstName'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                               Expanded( | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   controller: middleNameController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'middleName'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                               Expanded( | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   controller: lastNameController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'lastName'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           Row( | ||||||
|  |                             spacing: 16, | ||||||
|  |                             children: [ | ||||||
|  |                               Expanded( | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   controller: genderController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'gender'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                               Expanded( | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   controller: pronounsController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'pronouns'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           Row( | ||||||
|  |                             spacing: 16, | ||||||
|  |                             children: [ | ||||||
|  |                               Expanded( | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   controller: locationController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'location'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                               Expanded( | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   controller: timeZoneController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'timeZone'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           GestureDetector( | ||||||
|  |                             onTap: () async { | ||||||
|  |                               final date = await showDatePicker( | ||||||
|  |                                 context: context, | ||||||
|  |                                 initialDate: birthday.value ?? DateTime.now(), | ||||||
|  |                                 firstDate: DateTime(1900), | ||||||
|  |                                 lastDate: DateTime.now(), | ||||||
|  |                               ); | ||||||
|  |                               if (date != null) { | ||||||
|  |                                 birthday.value = date; | ||||||
|  |                               } | ||||||
|  |                             }, | ||||||
|  |                             child: Container( | ||||||
|  |                               padding: const EdgeInsets.symmetric(vertical: 8), | ||||||
|  |                               decoration: BoxDecoration( | ||||||
|  |                                 border: Border( | ||||||
|  |                                   bottom: BorderSide( | ||||||
|  |                                     color: Theme.of(context).dividerColor, | ||||||
|  |                                     width: 1, | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                               child: Column( | ||||||
|  |                                 crossAxisAlignment: CrossAxisAlignment.stretch, | ||||||
|  |                                 children: [ | ||||||
|  |                                   Text( | ||||||
|  |                                     'birthday'.tr(), | ||||||
|  |                                     style: TextStyle( | ||||||
|  |                                       color: Theme.of(context).hintColor, | ||||||
|  |                                     ), | ||||||
|  |                                   ), | ||||||
|  |                                   Text( | ||||||
|  |                                     birthday.value != null | ||||||
|  |                                         ? DateFormat.yMMMd().format( | ||||||
|  |                                           birthday.value!, | ||||||
|  |                                         ) | ||||||
|  |                                         : 'Select a date'.tr(), | ||||||
|  |                                   ), | ||||||
|  |                                 ], | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                           const SizedBox(height: 16), | ||||||
|  |                           Align( | ||||||
|  |                             alignment: Alignment.centerRight, | ||||||
|  |                             child: TextButton.icon( | ||||||
|  |                               onPressed: | ||||||
|  |                                   submitting.value ? null : performAction, | ||||||
|  |                               label: Text('saveChanges').tr(), | ||||||
|  |                               icon: const Icon(Symbols.save), | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ).padding(all: 24), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										167
									
								
								lib/screens/developers/edit_bot.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								lib/screens/developers/edit_bot.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'edit_bot.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // RiverpodGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | String _$botHash() => r'7bec47bb2a4061a5babc6d6d19c3d4c320c91188'; | ||||||
|  |  | ||||||
|  | /// 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 [bot]. | ||||||
|  | @ProviderFor(bot) | ||||||
|  | const botProvider = BotFamily(); | ||||||
|  |  | ||||||
|  | /// See also [bot]. | ||||||
|  | class BotFamily extends Family<AsyncValue<Bot?>> { | ||||||
|  |   /// See also [bot]. | ||||||
|  |   const BotFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [bot]. | ||||||
|  |   BotProvider call(String publisherName, String projectId, String id) { | ||||||
|  |     return BotProvider(publisherName, projectId, id); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   BotProvider getProviderOverride(covariant BotProvider provider) { | ||||||
|  |     return call(provider.publisherName, provider.projectId, 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'botProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [bot]. | ||||||
|  | class BotProvider extends AutoDisposeFutureProvider<Bot?> { | ||||||
|  |   /// See also [bot]. | ||||||
|  |   BotProvider(String publisherName, String projectId, String id) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => bot(ref as BotRef, publisherName, projectId, id), | ||||||
|  |         from: botProvider, | ||||||
|  |         name: r'botProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') ? null : _$botHash, | ||||||
|  |         dependencies: BotFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: BotFamily._allTransitiveDependencies, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         id: id, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   BotProvider._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.id, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   final String id; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith(FutureOr<Bot?> Function(BotRef provider) create) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: BotProvider._internal( | ||||||
|  |         (ref) => create(ref as BotRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         publisherName: publisherName, | ||||||
|  |         projectId: projectId, | ||||||
|  |         id: id, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<Bot?> createElement() { | ||||||
|  |     return _BotProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is BotProvider && | ||||||
|  |         other.publisherName == publisherName && | ||||||
|  |         other.projectId == projectId && | ||||||
|  |         other.id == id; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @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, id.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin BotRef on AutoDisposeFutureProviderRef<Bot?> { | ||||||
|  |   /// The parameter `publisherName` of this provider. | ||||||
|  |   String get publisherName; | ||||||
|  |  | ||||||
|  |   /// The parameter `projectId` of this provider. | ||||||
|  |   String get projectId; | ||||||
|  |  | ||||||
|  |   /// The parameter `id` of this provider. | ||||||
|  |   String get id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _BotProviderElement extends AutoDisposeFutureProviderElement<Bot?> | ||||||
|  |     with BotRef { | ||||||
|  |   _BotProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get publisherName => (origin as BotProvider).publisherName; | ||||||
|  |   @override | ||||||
|  |   String get projectId => (origin as BotProvider).projectId; | ||||||
|  |   @override | ||||||
|  |   String get id => (origin as BotProvider).id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ignore_for_file: type=lint | ||||||
|  | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
							
								
								
									
										130
									
								
								lib/screens/developers/edit_project.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								lib/screens/developers/edit_project.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:easy_localization/easy_localization.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/dev_project.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/screens/developers/projects.dart'; | ||||||
|  | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|  | import 'package:island/widgets/response.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  | import 'package:styled_widget/styled_widget.dart'; | ||||||
|  |  | ||||||
|  | part 'edit_project.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<DevProject?> devProject(Ref ref, String pubName, String id) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await client.get('/develop/developers/$pubName/projects/$id'); | ||||||
|  |   return DevProject.fromJson(resp.data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class EditProjectScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String? id; | ||||||
|  |   const EditProjectScreen({super.key, required this.publisherName, this.id}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final isNew = id == null; | ||||||
|  |     final projectData = | ||||||
|  |         isNew ? null : ref.watch(devProjectProvider(publisherName, id!)); | ||||||
|  |  | ||||||
|  |     final formKey = useMemoized(() => GlobalKey<FormState>()); | ||||||
|  |     final submitting = useState(false); | ||||||
|  |  | ||||||
|  |     final nameController = useTextEditingController(); | ||||||
|  |     final slugController = useTextEditingController(); | ||||||
|  |     final descriptionController = useTextEditingController(); | ||||||
|  |  | ||||||
|  |     useEffect(() { | ||||||
|  |       if (projectData?.value != null) { | ||||||
|  |         nameController.text = projectData!.value!.name; | ||||||
|  |         slugController.text = projectData.value!.slug; | ||||||
|  |         descriptionController.text = projectData.value!.description ?? ''; | ||||||
|  |       } | ||||||
|  |       return null; | ||||||
|  |     }, [projectData]); | ||||||
|  |  | ||||||
|  |     void performAction() async { | ||||||
|  |       final client = ref.read(apiClientProvider); | ||||||
|  |       final data = { | ||||||
|  |         'name': nameController.text, | ||||||
|  |         'slug': slugController.text, | ||||||
|  |         'description': descriptionController.text, | ||||||
|  |       }; | ||||||
|  |       if (isNew) { | ||||||
|  |         await client.post( | ||||||
|  |           '/develop/developers/$publisherName/projects', | ||||||
|  |           data: data, | ||||||
|  |         ); | ||||||
|  |       } else { | ||||||
|  |         await client.put( | ||||||
|  |           '/develop/developers/$publisherName/projects/$id', | ||||||
|  |           data: data, | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |       ref.invalidate(devProjectsProvider(publisherName)); | ||||||
|  |       if (context.mounted) { | ||||||
|  |         context.pop(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: Text(isNew ? 'createProject'.tr() : 'editProject'.tr()), | ||||||
|  |       ), | ||||||
|  |       body: | ||||||
|  |           projectData == null && !isNew | ||||||
|  |               ? const Center(child: CircularProgressIndicator()) | ||||||
|  |               : projectData?.hasError == true && !isNew | ||||||
|  |               ? ResponseErrorWidget( | ||||||
|  |                 error: projectData!.error, | ||||||
|  |                 onRetry: | ||||||
|  |                     () => | ||||||
|  |                         ref.invalidate(devProjectProvider(publisherName, id!)), | ||||||
|  |               ) | ||||||
|  |               : SingleChildScrollView( | ||||||
|  |                 child: Form( | ||||||
|  |                   key: formKey, | ||||||
|  |                   child: Column( | ||||||
|  |                     children: [ | ||||||
|  |                       TextFormField( | ||||||
|  |                         controller: nameController, | ||||||
|  |                         decoration: InputDecoration(labelText: 'name'.tr()), | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 16), | ||||||
|  |                       TextFormField( | ||||||
|  |                         controller: slugController, | ||||||
|  |                         decoration: InputDecoration( | ||||||
|  |                           labelText: 'slug'.tr(), | ||||||
|  |                           helperText: 'slugHint'.tr(), | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 16), | ||||||
|  |                       TextFormField( | ||||||
|  |                         controller: descriptionController, | ||||||
|  |                         decoration: InputDecoration( | ||||||
|  |                           labelText: 'description'.tr(), | ||||||
|  |                           alignLabelWithHint: true, | ||||||
|  |                         ), | ||||||
|  |                         maxLines: 3, | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 16), | ||||||
|  |                       Align( | ||||||
|  |                         alignment: Alignment.centerRight, | ||||||
|  |                         child: TextButton.icon( | ||||||
|  |                           onPressed: submitting.value ? null : performAction, | ||||||
|  |                           label: Text('saveChanges'.tr()), | ||||||
|  |                           icon: const Icon(Symbols.save), | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                     ], | ||||||
|  |                   ).padding(all: 24), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										163
									
								
								lib/screens/developers/edit_project.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								lib/screens/developers/edit_project.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'edit_project.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // RiverpodGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | String _$devProjectHash() => r'd92be3f5cdc510c2a377615ed5c70622a6842bf2'; | ||||||
|  |  | ||||||
|  | /// 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 [devProject]. | ||||||
|  | @ProviderFor(devProject) | ||||||
|  | const devProjectProvider = DevProjectFamily(); | ||||||
|  |  | ||||||
|  | /// See also [devProject]. | ||||||
|  | class DevProjectFamily extends Family<AsyncValue<DevProject?>> { | ||||||
|  |   /// See also [devProject]. | ||||||
|  |   const DevProjectFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [devProject]. | ||||||
|  |   DevProjectProvider call(String pubName, String id) { | ||||||
|  |     return DevProjectProvider(pubName, id); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   DevProjectProvider getProviderOverride( | ||||||
|  |     covariant DevProjectProvider provider, | ||||||
|  |   ) { | ||||||
|  |     return call(provider.pubName, 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'devProjectProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [devProject]. | ||||||
|  | class DevProjectProvider extends AutoDisposeFutureProvider<DevProject?> { | ||||||
|  |   /// See also [devProject]. | ||||||
|  |   DevProjectProvider(String pubName, String id) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => devProject(ref as DevProjectRef, pubName, id), | ||||||
|  |         from: devProjectProvider, | ||||||
|  |         name: r'devProjectProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$devProjectHash, | ||||||
|  |         dependencies: DevProjectFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: DevProjectFamily._allTransitiveDependencies, | ||||||
|  |         pubName: pubName, | ||||||
|  |         id: id, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   DevProjectProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.pubName, | ||||||
|  |     required this.id, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String pubName; | ||||||
|  |   final String id; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<DevProject?> Function(DevProjectRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: DevProjectProvider._internal( | ||||||
|  |         (ref) => create(ref as DevProjectRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         pubName: pubName, | ||||||
|  |         id: id, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<DevProject?> createElement() { | ||||||
|  |     return _DevProjectProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is DevProjectProvider && | ||||||
|  |         other.pubName == pubName && | ||||||
|  |         other.id == id; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, pubName.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 DevProjectRef on AutoDisposeFutureProviderRef<DevProject?> { | ||||||
|  |   /// The parameter `pubName` of this provider. | ||||||
|  |   String get pubName; | ||||||
|  |  | ||||||
|  |   /// The parameter `id` of this provider. | ||||||
|  |   String get id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _DevProjectProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<DevProject?> | ||||||
|  |     with DevProjectRef { | ||||||
|  |   _DevProjectProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get pubName => (origin as DevProjectProvider).pubName; | ||||||
|  |   @override | ||||||
|  |   String get id => (origin as DevProjectProvider).id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ignore_for_file: type=lint | ||||||
|  | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package | ||||||
| @@ -235,15 +235,15 @@ class DeveloperHubScreen extends HookConsumerWidget { | |||||||
|                             ).padding(vertical: 12, horizontal: 12), |                             ).padding(vertical: 12, horizontal: 12), | ||||||
|                           ListTile( |                           ListTile( | ||||||
|                             minTileHeight: 48, |                             minTileHeight: 48, | ||||||
|                             title: Text('customApps').tr(), |                             title: Text('projects').tr(), | ||||||
|                             trailing: Icon(Symbols.chevron_right), |                             trailing: const Icon(Symbols.chevron_right), | ||||||
|                             leading: const Icon(Symbols.apps), |                             leading: const Icon(Symbols.folder_managed), | ||||||
|                             contentPadding: EdgeInsets.symmetric( |                             contentPadding: const EdgeInsets.symmetric( | ||||||
|                               horizontal: 24, |                               horizontal: 24, | ||||||
|                             ), |                             ), | ||||||
|                             onTap: () { |                             onTap: () { | ||||||
|                               context.pushNamed( |                               context.pushNamed( | ||||||
|                                 'developerApps', |                                 'developerProjects', | ||||||
|                                 pathParameters: { |                                 pathParameters: { | ||||||
|                                   'name': |                                   'name': | ||||||
|                                       currentDeveloper.value!.publisher!.name, |                                       currentDeveloper.value!.publisher!.name, | ||||||
|   | |||||||
| @@ -3,10 +3,11 @@ import 'package:island/screens/developers/edit_app.dart'; | |||||||
|  |  | ||||||
| class NewCustomAppScreen extends StatelessWidget { | class NewCustomAppScreen extends StatelessWidget { | ||||||
|   final String publisherName; |   final String publisherName; | ||||||
|   const NewCustomAppScreen({super.key, required this.publisherName}); |   final String projectId; | ||||||
|  |   const NewCustomAppScreen({super.key, required this.publisherName, required this.projectId}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return EditAppScreen(publisherName: publisherName); |     return EditAppScreen(publisherName: publisherName, projectId: projectId); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								lib/screens/developers/new_bot.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/screens/developers/new_bot.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  |  | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:island/screens/developers/edit_bot.dart'; | ||||||
|  |  | ||||||
|  | class NewBotScreen extends StatelessWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |   const NewBotScreen({super.key, required this.publisherName, required this.projectId}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return EditBotScreen(publisherName: publisherName, projectId: projectId); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								lib/screens/developers/new_project.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/screens/developers/new_project.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  |  | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:island/screens/developers/edit_project.dart'; | ||||||
|  |  | ||||||
|  | class NewProjectScreen extends StatelessWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   const NewProjectScreen({super.key, required this.publisherName}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return EditProjectScreen(publisherName: publisherName); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										92
									
								
								lib/screens/developers/project_detail.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								lib/screens/developers/project_detail.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_hooks/flutter_hooks.dart'; | ||||||
|  | import 'package:gap/gap.dart'; | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/screens/developers/apps.dart'; | ||||||
|  | import 'package:island/screens/developers/bots.dart'; | ||||||
|  | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  |  | ||||||
|  | class ProjectDetailScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   final String projectId; | ||||||
|  |  | ||||||
|  |   const ProjectDetailScreen({ | ||||||
|  |     super.key, | ||||||
|  |     required this.publisherName, | ||||||
|  |     required this.projectId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final tabController = useTabController(initialLength: 2); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: Text('projectDetails').tr(), | ||||||
|  |         actions: [ | ||||||
|  |           IconButton( | ||||||
|  |             icon: const Icon(Symbols.add), | ||||||
|  |             onPressed: () { | ||||||
|  |               // Get current tab index | ||||||
|  |               final index = tabController.index; | ||||||
|  |               switch (index) { | ||||||
|  |                 case 0: | ||||||
|  |                   context.pushNamed( | ||||||
|  |                     'developerAppNew', | ||||||
|  |                     pathParameters: { | ||||||
|  |                       'name': publisherName, | ||||||
|  |                       'projectId': projectId, | ||||||
|  |                     }, | ||||||
|  |                   ); | ||||||
|  |                   break; | ||||||
|  |                 case 1: | ||||||
|  |                   context.pushNamed( | ||||||
|  |                     'developerBotNew', | ||||||
|  |                     pathParameters: { | ||||||
|  |                       'name': publisherName, | ||||||
|  |                       'projectId': projectId, | ||||||
|  |                     }, | ||||||
|  |                   ); | ||||||
|  |                   break; | ||||||
|  |               } | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|  |           const Gap(8), | ||||||
|  |         ], | ||||||
|  |         bottom: TabBar( | ||||||
|  |           controller: tabController, | ||||||
|  |           tabs: [ | ||||||
|  |             Tab( | ||||||
|  |               child: Text( | ||||||
|  |                 'customApps'.tr(), | ||||||
|  |                 textAlign: TextAlign.center, | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             Tab( | ||||||
|  |               child: Text( | ||||||
|  |                 'bots'.tr(), | ||||||
|  |                 textAlign: TextAlign.center, | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: Theme.of(context).appBarTheme.foregroundColor!, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |       body: TabBarView( | ||||||
|  |         controller: tabController, | ||||||
|  |         children: [ | ||||||
|  |           CustomAppsScreen(publisherName: publisherName, projectId: projectId), | ||||||
|  |           BotsScreen(publisherName: publisherName, projectId: projectId), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										150
									
								
								lib/screens/developers/projects.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								lib/screens/developers/projects.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:gap/gap.dart'; | ||||||
|  | import 'package:go_router/go_router.dart'; | ||||||
|  | import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||||
|  | import 'package:island/models/dev_project.dart'; | ||||||
|  | import 'package:island/pods/network.dart'; | ||||||
|  | import 'package:island/widgets/alert.dart'; | ||||||
|  | import 'package:island/widgets/app_scaffold.dart'; | ||||||
|  | import 'package:island/widgets/response.dart'; | ||||||
|  | import 'package:material_symbols_icons/symbols.dart'; | ||||||
|  | import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||||
|  |  | ||||||
|  | part 'projects.g.dart'; | ||||||
|  |  | ||||||
|  | @riverpod | ||||||
|  | Future<List<DevProject>> devProjects(Ref ref, String pubName) async { | ||||||
|  |   final client = ref.watch(apiClientProvider); | ||||||
|  |   final resp = await client.get('/develop/developers/$pubName/projects'); | ||||||
|  |   return (resp.data as List) | ||||||
|  |       .map((e) => DevProject.fromJson(e)) | ||||||
|  |       .cast<DevProject>() | ||||||
|  |       .toList(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class DevProjectsScreen extends HookConsumerWidget { | ||||||
|  |   final String publisherName; | ||||||
|  |   const DevProjectsScreen({super.key, required this.publisherName}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context, WidgetRef ref) { | ||||||
|  |     final projects = ref.watch(devProjectsProvider(publisherName)); | ||||||
|  |  | ||||||
|  |     return AppScaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: Text('projects').tr(), | ||||||
|  |         actions: [ | ||||||
|  |           IconButton( | ||||||
|  |             icon: const Icon(Symbols.add), | ||||||
|  |             onPressed: () { | ||||||
|  |               context.pushNamed( | ||||||
|  |                 'developerProjectNew', | ||||||
|  |                 pathParameters: {'name': publisherName}, | ||||||
|  |               ); | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|  |           const Gap(8), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |       body: projects.when( | ||||||
|  |         data: (data) { | ||||||
|  |           if (data.isEmpty) { | ||||||
|  |             return Center(child: Text('noProjects').tr()); | ||||||
|  |           } | ||||||
|  |           return RefreshIndicator( | ||||||
|  |             onRefresh: | ||||||
|  |                 () => ref.refresh(devProjectsProvider(publisherName).future), | ||||||
|  |             child: ListView.builder( | ||||||
|  |               padding: EdgeInsets.only(top: 4), | ||||||
|  |               itemCount: data.length, | ||||||
|  |               itemBuilder: (context, index) { | ||||||
|  |                 final project = data[index]; | ||||||
|  |                 return Card( | ||||||
|  |                   margin: const EdgeInsets.all(8.0), | ||||||
|  |                   child: ListTile( | ||||||
|  |                     shape: RoundedRectangleBorder( | ||||||
|  |                       borderRadius: BorderRadius.circular(8.0), | ||||||
|  |                     ), | ||||||
|  |                     contentPadding: EdgeInsets.only(left: 20, right: 12), | ||||||
|  |                     title: Text(project.name), | ||||||
|  |                     subtitle: Text(project.description ?? ''), | ||||||
|  |                     trailing: PopupMenuButton( | ||||||
|  |                       itemBuilder: | ||||||
|  |                           (context) => [ | ||||||
|  |                             PopupMenuItem( | ||||||
|  |                               value: 'edit', | ||||||
|  |                               child: Row( | ||||||
|  |                                 children: [ | ||||||
|  |                                   const Icon(Symbols.edit), | ||||||
|  |                                   const SizedBox(width: 12), | ||||||
|  |                                   Text('edit').tr(), | ||||||
|  |                                 ], | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                             PopupMenuItem( | ||||||
|  |                               value: 'delete', | ||||||
|  |                               child: Row( | ||||||
|  |                                 children: [ | ||||||
|  |                                   const Icon(Symbols.delete, color: Colors.red), | ||||||
|  |                                   const SizedBox(width: 12), | ||||||
|  |                                   Text( | ||||||
|  |                                     'delete', | ||||||
|  |                                     style: TextStyle(color: Colors.red), | ||||||
|  |                                   ).tr(), | ||||||
|  |                                 ], | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                           ], | ||||||
|  |                       onSelected: (value) { | ||||||
|  |                         if (value == 'edit') { | ||||||
|  |                           context.pushNamed( | ||||||
|  |                             'developerProjectEdit', | ||||||
|  |                             pathParameters: { | ||||||
|  |                               'name': publisherName, | ||||||
|  |                               'id': project.id, | ||||||
|  |                             }, | ||||||
|  |                           ); | ||||||
|  |                         } else if (value == 'delete') { | ||||||
|  |                           showConfirmAlert( | ||||||
|  |                             'deleteProjectHint'.tr(), | ||||||
|  |                             'deleteProject'.tr(), | ||||||
|  |                           ).then((confirm) { | ||||||
|  |                             if (confirm) { | ||||||
|  |                               final client = ref.read(apiClientProvider); | ||||||
|  |                               client.delete( | ||||||
|  |                                 '/develop/developers/$publisherName/projects/${project.id}', | ||||||
|  |                               ); | ||||||
|  |                               ref.invalidate( | ||||||
|  |                                 devProjectsProvider(publisherName), | ||||||
|  |                               ); | ||||||
|  |                             } | ||||||
|  |                           }); | ||||||
|  |                         } | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                     onTap: () { | ||||||
|  |                       context.pushNamed( | ||||||
|  |                         'developerProjectDetail', | ||||||
|  |                         pathParameters: { | ||||||
|  |                           'name': publisherName, | ||||||
|  |                           'projectId': project.id, | ||||||
|  |                         }, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                 ); | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |         loading: () => const Center(child: CircularProgressIndicator()), | ||||||
|  |         error: | ||||||
|  |             (err, stack) => ResponseErrorWidget( | ||||||
|  |               error: err, | ||||||
|  |               onRetry: () => ref.invalidate(devProjectsProvider(publisherName)), | ||||||
|  |             ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										151
									
								
								lib/screens/developers/projects.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								lib/screens/developers/projects.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | |||||||
|  | // GENERATED CODE - DO NOT MODIFY BY HAND | ||||||
|  |  | ||||||
|  | part of 'projects.dart'; | ||||||
|  |  | ||||||
|  | // ************************************************************************** | ||||||
|  | // RiverpodGenerator | ||||||
|  | // ************************************************************************** | ||||||
|  |  | ||||||
|  | String _$devProjectsHash() => r'87fdcab47cd7d79ab019a5625617abeb1ffa1f39'; | ||||||
|  |  | ||||||
|  | /// 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 [devProjects]. | ||||||
|  | @ProviderFor(devProjects) | ||||||
|  | const devProjectsProvider = DevProjectsFamily(); | ||||||
|  |  | ||||||
|  | /// See also [devProjects]. | ||||||
|  | class DevProjectsFamily extends Family<AsyncValue<List<DevProject>>> { | ||||||
|  |   /// See also [devProjects]. | ||||||
|  |   const DevProjectsFamily(); | ||||||
|  |  | ||||||
|  |   /// See also [devProjects]. | ||||||
|  |   DevProjectsProvider call(String pubName) { | ||||||
|  |     return DevProjectsProvider(pubName); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   DevProjectsProvider getProviderOverride( | ||||||
|  |     covariant DevProjectsProvider provider, | ||||||
|  |   ) { | ||||||
|  |     return call(provider.pubName); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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'devProjectsProvider'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// See also [devProjects]. | ||||||
|  | class DevProjectsProvider extends AutoDisposeFutureProvider<List<DevProject>> { | ||||||
|  |   /// See also [devProjects]. | ||||||
|  |   DevProjectsProvider(String pubName) | ||||||
|  |     : this._internal( | ||||||
|  |         (ref) => devProjects(ref as DevProjectsRef, pubName), | ||||||
|  |         from: devProjectsProvider, | ||||||
|  |         name: r'devProjectsProvider', | ||||||
|  |         debugGetCreateSourceHash: | ||||||
|  |             const bool.fromEnvironment('dart.vm.product') | ||||||
|  |                 ? null | ||||||
|  |                 : _$devProjectsHash, | ||||||
|  |         dependencies: DevProjectsFamily._dependencies, | ||||||
|  |         allTransitiveDependencies: DevProjectsFamily._allTransitiveDependencies, | ||||||
|  |         pubName: pubName, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |   DevProjectsProvider._internal( | ||||||
|  |     super._createNotifier, { | ||||||
|  |     required super.name, | ||||||
|  |     required super.dependencies, | ||||||
|  |     required super.allTransitiveDependencies, | ||||||
|  |     required super.debugGetCreateSourceHash, | ||||||
|  |     required super.from, | ||||||
|  |     required this.pubName, | ||||||
|  |   }) : super.internal(); | ||||||
|  |  | ||||||
|  |   final String pubName; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Override overrideWith( | ||||||
|  |     FutureOr<List<DevProject>> Function(DevProjectsRef provider) create, | ||||||
|  |   ) { | ||||||
|  |     return ProviderOverride( | ||||||
|  |       origin: this, | ||||||
|  |       override: DevProjectsProvider._internal( | ||||||
|  |         (ref) => create(ref as DevProjectsRef), | ||||||
|  |         from: from, | ||||||
|  |         name: null, | ||||||
|  |         dependencies: null, | ||||||
|  |         allTransitiveDependencies: null, | ||||||
|  |         debugGetCreateSourceHash: null, | ||||||
|  |         pubName: pubName, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   AutoDisposeFutureProviderElement<List<DevProject>> createElement() { | ||||||
|  |     return _DevProjectsProviderElement(this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool operator ==(Object other) { | ||||||
|  |     return other is DevProjectsProvider && other.pubName == pubName; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   int get hashCode { | ||||||
|  |     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||||
|  |     hash = _SystemHash.combine(hash, pubName.hashCode); | ||||||
|  |  | ||||||
|  |     return _SystemHash.finish(hash); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
|  | // ignore: unused_element | ||||||
|  | mixin DevProjectsRef on AutoDisposeFutureProviderRef<List<DevProject>> { | ||||||
|  |   /// The parameter `pubName` of this provider. | ||||||
|  |   String get pubName; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _DevProjectsProviderElement | ||||||
|  |     extends AutoDisposeFutureProviderElement<List<DevProject>> | ||||||
|  |     with DevProjectsRef { | ||||||
|  |   _DevProjectsProviderElement(super.provider); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String get pubName => (origin as DevProjectsProvider).pubName; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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 | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user