Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
188b6821a2
|
|||
|
0ebbe0bd5a
|
|||
|
46a826ff86
|
|||
|
1d99ac6441
|
|||
|
e2efdc4064
|
|||
|
cba1a3884b
|
|||
|
7147ce1efa
|
|||
|
78c1a284a5
|
|||
|
f1f5113b01
|
|||
|
a44552f105
|
|||
|
8c1ad94555
|
|||
|
84f5677260
|
|||
|
aa1ffdbf10
|
|||
|
c24d13461b
|
|||
|
3b60fcb87c
|
|||
|
3605b997b1
|
|||
|
800815c721
|
|||
|
3b13a63e7b
|
|||
|
81d69ce10f
|
|||
|
c16d8a5912
|
|||
|
cb9eca0424
|
|||
|
d7858bab67
|
|||
|
5ce590029b
|
|||
|
4d92dec45c
|
|||
|
0a4e797eec
|
|||
|
38dffa414f
|
|||
|
eea56a742e
|
|||
|
56b7ee1d69
|
|||
|
3b564f7e7f
|
|||
|
93d2670063
|
|||
|
788165ac5b
|
|||
|
ec71125fa9
|
|||
|
adb231278c
|
|||
|
b3ae4ab36f
|
|||
|
3670fe0f10
|
|||
|
bb1a5155ed
|
|||
|
eb90dbbc5a
|
|||
|
a73d9f8ec0
|
|||
|
4c8f2e3251
|
|||
|
bc9d2ab8ce
|
|||
|
8bc01f1b97
|
|||
|
200cf3ec80
|
|||
|
d910d837eb
|
|||
|
56d1f14206
|
|||
|
a7c8a8d2ee
|
|||
|
411c71dae0
|
|||
|
a8430604f9
|
|||
|
fe37d219b7
|
|||
|
bc1ebc799a
|
|||
|
37940ef12a
|
|||
|
5d0469e187
|
|||
|
7ad7ab53a6
|
|||
|
6b0343d3dc
|
|||
|
f541580281
|
|||
|
6e7eedc026
|
|||
|
5d5bda7925
|
|||
|
48e66580c3
|
|||
|
836449e3f4
|
|||
|
804dd029b1
|
|||
|
e13928b03f
|
|||
|
5c14236603
|
File diff suppressed because it is too large
Load Diff
@@ -158,7 +158,7 @@
|
||||
"checkIn": "Check In",
|
||||
"checkInNone": "Not checked-in yet",
|
||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||
"checkInResultLevel0": "Wrost Luck",
|
||||
"checkInResultLevel0": "Worst Luck",
|
||||
"checkInResultLevel1": "Bad Luck",
|
||||
"checkInResultLevel2": "A Normal Day",
|
||||
"checkInResultLevel3": "Good Luck",
|
||||
@@ -314,7 +314,6 @@
|
||||
"settingsAutoTranslate": "Auto Translate",
|
||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||
"settingsSoundEffects": "Sound Effects",
|
||||
"settingsAprilFoolFeatures": "April Fool Features",
|
||||
"settingsEnterToSend": "Enter to Send",
|
||||
"settingsTransparentAppBar": "Transparent App Bar",
|
||||
"settingsCustomFonts": "Custom Fonts",
|
||||
@@ -682,9 +681,9 @@
|
||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||
"postVisibility": "Post Visibility",
|
||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||
"sharePostPhoto": "Share Post as Photo",
|
||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||
"abuseReports": "Abuse Reports",
|
||||
@@ -705,7 +704,7 @@
|
||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||
"aboutScreenContactUsTitle": "Contact Us",
|
||||
"aboutScreenLicenseTitle": "License",
|
||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
||||
"aboutScreenLicenseContent": "AGPLv3",
|
||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||
@@ -1474,5 +1473,74 @@
|
||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||
"dropToShare": "Drop to share"
|
||||
"dropToShare": "Drop to share",
|
||||
"affiliationSpell": "Affiliation Spell",
|
||||
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||
"friendsOnline": "Friends Online",
|
||||
"createAccountAlmostThere": "Almost There",
|
||||
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||
"createAccountNotice": "Things you need to know before you create an account:",
|
||||
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||
"createAccountProfile": "Create your profile",
|
||||
"createAccountToS": "Review Terms & Conditions",
|
||||
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||
"realmsDescription": "Manage realms you've joined.",
|
||||
"exploreDescription": "Explore contents on the Solar Network.",
|
||||
"accountDescription": "Information about your account.",
|
||||
"chatDescription": "Group Chats and Direct Messages",
|
||||
"connectionServerDown": "Unable to Connect",
|
||||
"appSettingsDescription": "Customize your app.",
|
||||
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||
"walletDescription": "Your source point wallet.",
|
||||
"relationshipsDescription": "Friends and connections.",
|
||||
"notificationsDescription": "See what's happended related to you recently.",
|
||||
"settingsFestivalFeatures": "Festival Limited Features",
|
||||
"categoriesAndTags": "Categories & Tags",
|
||||
"webArticlesStandDescription": "Explore external sites articles.",
|
||||
"aboutDescription": "Learn more about the Solar Network.",
|
||||
"abuseReportsDescription": "View and manage abuse reports.",
|
||||
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||
"levelingDescription": "See your leveling progress and history.",
|
||||
"notableDayToday": "{} is today!",
|
||||
"authSessionLogout": "Logout Session",
|
||||
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||
"postComposeDescription": "Compose a new post",
|
||||
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||
"accountActivationAlert": "Activate your account",
|
||||
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||
"accountActivationResend": "Resend",
|
||||
"ipAddress": "IP Address",
|
||||
"noFurtherData": "No further data",
|
||||
"searchAnything": "Search Anything...",
|
||||
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||
"mostRecent": "Most Recent",
|
||||
"noNotificationsYet": "No notifications yet",
|
||||
"recentChats": "Recent Chats",
|
||||
"noFeaturedPostsAvailable": "No featured posts available",
|
||||
"searchChatsAndPages": "Search chats and pages...",
|
||||
"dashboard": "Dashboard",
|
||||
"dashboardDescription": "All your data in one place.",
|
||||
"postTagsCategories": "Post Tags and Categories",
|
||||
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||
"debugLogs": "Debug Logs",
|
||||
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||
"pinChatRoom": "Pin Chat Room",
|
||||
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||
"chatRoomPinned": "Chat room pinned successfully.",
|
||||
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||
"pinnedChatRoom": "Pinned Rooms",
|
||||
"settingsGroupedChatList": "Grouped Chat List",
|
||||
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||
"settingsDashSearchEngine": "Search Engine for web",
|
||||
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||
"settingsDefaultScreen": "Default Screen",
|
||||
"notableDayChristmas": "Christmas",
|
||||
"notableDayNewYear": "New Year"
|
||||
}
|
||||
@@ -158,7 +158,7 @@
|
||||
"checkIn": "Check In",
|
||||
"checkInNone": "Not checked-in yet",
|
||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||
"checkInResultLevel0": "Wrost Luck",
|
||||
"checkInResultLevel0": "Worst Luck",
|
||||
"checkInResultLevel1": "Bad Luck",
|
||||
"checkInResultLevel2": "A Normal Day",
|
||||
"checkInResultLevel3": "Good Luck",
|
||||
@@ -314,7 +314,6 @@
|
||||
"settingsAutoTranslate": "Auto Translate",
|
||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||
"settingsSoundEffects": "Sound Effects",
|
||||
"settingsAprilFoolFeatures": "April Fool Features",
|
||||
"settingsEnterToSend": "Enter to Send",
|
||||
"settingsTransparentAppBar": "Transparent App Bar",
|
||||
"settingsCustomFonts": "Custom Fonts",
|
||||
@@ -682,9 +681,9 @@
|
||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||
"postVisibility": "Post Visibility",
|
||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||
"sharePostPhoto": "Share Post as Photo",
|
||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||
"abuseReports": "Abuse Reports",
|
||||
@@ -705,7 +704,7 @@
|
||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||
"aboutScreenContactUsTitle": "Contact Us",
|
||||
"aboutScreenLicenseTitle": "License",
|
||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
||||
"aboutScreenLicenseContent": "AGPLv3",
|
||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||
@@ -1474,5 +1473,74 @@
|
||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||
"dropToShare": "Drop to share"
|
||||
"dropToShare": "Drop to share",
|
||||
"affiliationSpell": "Affiliation Spell",
|
||||
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||
"friendsOnline": "Friends Online",
|
||||
"createAccountAlmostThere": "Almost There",
|
||||
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||
"createAccountNotice": "Things you need to know before you create an account:",
|
||||
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||
"createAccountProfile": "Create your profile",
|
||||
"createAccountToS": "Review Terms & Conditions",
|
||||
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||
"realmsDescription": "Manage realms you've joined.",
|
||||
"exploreDescription": "Explore contents on the Solar Network.",
|
||||
"accountDescription": "Information about your account.",
|
||||
"chatDescription": "Group Chats and Direct Messages",
|
||||
"connectionServerDown": "Unable to Connect",
|
||||
"appSettingsDescription": "Customize your app.",
|
||||
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||
"walletDescription": "Your source point wallet.",
|
||||
"relationshipsDescription": "Friends and connections.",
|
||||
"notificationsDescription": "See what's happended related to you recently.",
|
||||
"settingsFestivalFeatures": "Festival Limited Features",
|
||||
"categoriesAndTags": "Categories & Tags",
|
||||
"webArticlesStandDescription": "Explore external sites articles.",
|
||||
"aboutDescription": "Learn more about the Solar Network.",
|
||||
"abuseReportsDescription": "View and manage abuse reports.",
|
||||
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||
"levelingDescription": "See your leveling progress and history.",
|
||||
"notableDayToday": "{} is today!",
|
||||
"authSessionLogout": "Logout Session",
|
||||
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||
"postComposeDescription": "Compose a new post",
|
||||
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||
"accountActivationAlert": "Activate your account",
|
||||
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||
"accountActivationResend": "Resend",
|
||||
"ipAddress": "IP Address",
|
||||
"noFurtherData": "No further data",
|
||||
"searchAnything": "Search Anything...",
|
||||
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||
"mostRecent": "Most Recent",
|
||||
"noNotificationsYet": "No notifications yet",
|
||||
"recentChats": "Recent Chats",
|
||||
"noFeaturedPostsAvailable": "No featured posts available",
|
||||
"searchChatsAndPages": "Search chats and pages...",
|
||||
"dashboard": "Dashboard",
|
||||
"dashboardDescription": "All your data in one place.",
|
||||
"postTagsCategories": "Post Tags and Categories",
|
||||
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||
"debugLogs": "Debug Logs",
|
||||
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||
"pinChatRoom": "Pin Chat Room",
|
||||
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||
"chatRoomPinned": "Chat room pinned successfully.",
|
||||
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||
"pinnedChatRoom": "Pinned Rooms",
|
||||
"settingsGroupedChatList": "Grouped Chat List",
|
||||
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||
"settingsDashSearchEngine": "Search Engine for web",
|
||||
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||
"settingsDefaultScreen": "Default Screen",
|
||||
"notableDayChristmas": "Christmas",
|
||||
"notableDayNewYear": "New Year"
|
||||
}
|
||||
@@ -158,7 +158,7 @@
|
||||
"checkIn": "Check In",
|
||||
"checkInNone": "Not checked-in yet",
|
||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||
"checkInResultLevel0": "Wrost Luck",
|
||||
"checkInResultLevel0": "Worst Luck",
|
||||
"checkInResultLevel1": "Bad Luck",
|
||||
"checkInResultLevel2": "A Normal Day",
|
||||
"checkInResultLevel3": "Good Luck",
|
||||
@@ -314,7 +314,6 @@
|
||||
"settingsAutoTranslate": "Auto Translate",
|
||||
"settingsHideBottomNav": "Hide Bottom Navigation",
|
||||
"settingsSoundEffects": "Sound Effects",
|
||||
"settingsAprilFoolFeatures": "April Fool Features",
|
||||
"settingsEnterToSend": "Enter to Send",
|
||||
"settingsTransparentAppBar": "Transparent App Bar",
|
||||
"settingsCustomFonts": "Custom Fonts",
|
||||
@@ -682,9 +681,9 @@
|
||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||
"postVisibility": "Post Visibility",
|
||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||
"sharePostPhoto": "Share Post as Photo",
|
||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||
"abuseReports": "Abuse Reports",
|
||||
@@ -705,7 +704,7 @@
|
||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||
"aboutScreenContactUsTitle": "Contact Us",
|
||||
"aboutScreenLicenseTitle": "License",
|
||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
||||
"aboutScreenLicenseContent": "AGPLv3",
|
||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||
@@ -1474,5 +1473,74 @@
|
||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||
"dropToShare": "Drop to share"
|
||||
"dropToShare": "Drop to share",
|
||||
"affiliationSpell": "Affiliation Spell",
|
||||
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||
"friendsOnline": "Friends Online",
|
||||
"createAccountAlmostThere": "Almost There",
|
||||
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||
"createAccountNotice": "Things you need to know before you create an account:",
|
||||
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||
"createAccountProfile": "Create your profile",
|
||||
"createAccountToS": "Review Terms & Conditions",
|
||||
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||
"realmsDescription": "Manage realms you've joined.",
|
||||
"exploreDescription": "Explore contents on the Solar Network.",
|
||||
"accountDescription": "Information about your account.",
|
||||
"chatDescription": "Group Chats and Direct Messages",
|
||||
"connectionServerDown": "Unable to Connect",
|
||||
"appSettingsDescription": "Customize your app.",
|
||||
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||
"walletDescription": "Your source point wallet.",
|
||||
"relationshipsDescription": "Friends and connections.",
|
||||
"notificationsDescription": "See what's happended related to you recently.",
|
||||
"settingsFestivalFeatures": "Festival Limited Features",
|
||||
"categoriesAndTags": "Categories & Tags",
|
||||
"webArticlesStandDescription": "Explore external sites articles.",
|
||||
"aboutDescription": "Learn more about the Solar Network.",
|
||||
"abuseReportsDescription": "View and manage abuse reports.",
|
||||
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||
"levelingDescription": "See your leveling progress and history.",
|
||||
"notableDayToday": "{} is today!",
|
||||
"authSessionLogout": "Logout Session",
|
||||
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||
"postComposeDescription": "Compose a new post",
|
||||
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||
"accountActivationAlert": "Activate your account",
|
||||
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||
"accountActivationResend": "Resend",
|
||||
"ipAddress": "IP Address",
|
||||
"noFurtherData": "No further data",
|
||||
"searchAnything": "Search Anything...",
|
||||
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||
"mostRecent": "Most Recent",
|
||||
"noNotificationsYet": "No notifications yet",
|
||||
"recentChats": "Recent Chats",
|
||||
"noFeaturedPostsAvailable": "No featured posts available",
|
||||
"searchChatsAndPages": "Search chats and pages...",
|
||||
"dashboard": "Dashboard",
|
||||
"dashboardDescription": "All your data in one place.",
|
||||
"postTagsCategories": "Post Tags and Categories",
|
||||
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||
"debugLogs": "Debug Logs",
|
||||
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||
"pinChatRoom": "Pin Chat Room",
|
||||
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||
"chatRoomPinned": "Chat room pinned successfully.",
|
||||
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||
"pinnedChatRoom": "Pinned Rooms",
|
||||
"settingsGroupedChatList": "Grouped Chat List",
|
||||
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||
"settingsDashSearchEngine": "Search Engine for web",
|
||||
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||
"settingsDefaultScreen": "Default Screen",
|
||||
"notableDayChristmas": "Christmas",
|
||||
"notableDayNewYear": "New Year"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -314,7 +314,6 @@
|
||||
"settingsAutoTranslate": "自轉譯",
|
||||
"settingsHideBottomNav": "隱底航",
|
||||
"settingsSoundEffects": "音效",
|
||||
"settingsAprilFoolFeatures": "謔辰妙能",
|
||||
"settingsEnterToSend": "叩回車鍵即送",
|
||||
"settingsTransparentAppBar": "透光應用欄",
|
||||
"settingsCustomFonts": "自定字體",
|
||||
@@ -328,13 +327,13 @@
|
||||
"accountDeletion": "除去此账户",
|
||||
"accountDeletionHint": "汝已存心除此账户?如已一意,信将至汝邮址,随信中之言续此行。",
|
||||
"accountDeletionSent": "除此账户之信已送至,请于汝之邮址查阅。",
|
||||
"accountSecurityTitle": "Security",
|
||||
"accountDangerZoneTitle": "Danger Zone",
|
||||
"accountSecurityTitle": "保护措施",
|
||||
"accountDangerZoneTitle": "危险地区",
|
||||
"accountPassword": "密碼",
|
||||
"accountPasswordDescription": "變更账户密碼",
|
||||
"accountPasswordChange": "變更密碼",
|
||||
"accountPasswordChangeSent": "Password reset link sent, please check your email inbox.",
|
||||
"accountPasswordChangeDescription": "We will send an email to your primary email address to reset your password.",
|
||||
"accountPasswordChangeSent": "密码重置链接已发送,请查看您的电子邮箱收件箱。",
|
||||
"accountPasswordChangeDescription": "我们将向您的主要电子邮箱发送一封邮件以重置您的密码。",
|
||||
"accountAuthFactor": "Auth factors",
|
||||
"accountAuthFactorDescription": "Multi-factor authentication to ensure safety and convience",
|
||||
"accountDeletionDescription": "Permanently delete your account and all your data",
|
||||
@@ -682,9 +681,9 @@
|
||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||
"postVisibility": "Post Visibility",
|
||||
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
||||
"membershipPriceStellar": "1200 NSP per month, level 20+ required",
|
||||
"membershipPriceNova": "2400 NSP per month, level 40+ required",
|
||||
"membershipPriceSupernova": "3600 NSP per month, level 60+ required",
|
||||
"sharePostPhoto": "Share Post as Photo",
|
||||
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||
"abuseReports": "Abuse Reports",
|
||||
@@ -705,7 +704,7 @@
|
||||
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||
"aboutScreenContactUsTitle": "Contact Us",
|
||||
"aboutScreenLicenseTitle": "License",
|
||||
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
|
||||
"aboutScreenLicenseContent": "AGPLv3",
|
||||
"aboutScreenCopyright": "All rights reserved © Solsynth {}",
|
||||
"aboutScreenMadeWith": "Made with ❤︎️ by Solar Network Team",
|
||||
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||
@@ -1474,5 +1473,74 @@
|
||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||
"dropToShare": "Drop to share"
|
||||
"dropToShare": "Drop to share",
|
||||
"affiliationSpell": "Affiliation Spell",
|
||||
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||
"friendsOnline": "Friends Online",
|
||||
"createAccountAlmostThere": "Almost There",
|
||||
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||
"createAccountNotice": "Things you need to know before you create an account:",
|
||||
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||
"createAccountProfile": "Create your profile",
|
||||
"createAccountToS": "Review Terms & Conditions",
|
||||
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||
"realmsDescription": "Manage realms you've joined.",
|
||||
"exploreDescription": "Explore contents on the Solar Network.",
|
||||
"accountDescription": "Information about your account.",
|
||||
"chatDescription": "Group Chats and Direct Messages",
|
||||
"connectionServerDown": "Unable to Connect",
|
||||
"appSettingsDescription": "Customize your app.",
|
||||
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||
"walletDescription": "Your source point wallet.",
|
||||
"relationshipsDescription": "Friends and connections.",
|
||||
"notificationsDescription": "See what's happended related to you recently.",
|
||||
"settingsFestivalFeatures": "Festival Limited Features",
|
||||
"categoriesAndTags": "Categories & Tags",
|
||||
"webArticlesStandDescription": "Explore external sites articles.",
|
||||
"aboutDescription": "Learn more about the Solar Network.",
|
||||
"abuseReportsDescription": "View and manage abuse reports.",
|
||||
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||
"levelingDescription": "See your leveling progress and history.",
|
||||
"notableDayToday": "{} is today!",
|
||||
"authSessionLogout": "Logout Session",
|
||||
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||
"postComposeDescription": "Compose a new post",
|
||||
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||
"accountActivationAlert": "Activate your account",
|
||||
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||
"accountActivationResend": "Resend",
|
||||
"ipAddress": "IP Address",
|
||||
"noFurtherData": "No further data",
|
||||
"searchAnything": "Search Anything...",
|
||||
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||
"mostRecent": "Most Recent",
|
||||
"noNotificationsYet": "No notifications yet",
|
||||
"recentChats": "Recent Chats",
|
||||
"noFeaturedPostsAvailable": "No featured posts available",
|
||||
"searchChatsAndPages": "Search chats and pages...",
|
||||
"dashboard": "Dashboard",
|
||||
"dashboardDescription": "All your data in one place.",
|
||||
"postTagsCategories": "Post Tags and Categories",
|
||||
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||
"debugLogs": "Debug Logs",
|
||||
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||
"pinChatRoom": "Pin Chat Room",
|
||||
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||
"chatRoomPinned": "Chat room pinned successfully.",
|
||||
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||
"pinnedChatRoom": "Pinned Rooms",
|
||||
"settingsGroupedChatList": "Grouped Chat List",
|
||||
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||
"settingsDashSearchEngine": "Search Engine for web",
|
||||
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||
"settingsDefaultScreen": "Default Screen",
|
||||
"notableDayChristmas": "Christmas",
|
||||
"notableDayNewYear": "New Year"
|
||||
}
|
||||
@@ -314,7 +314,6 @@
|
||||
"settingsAutoTranslate": "自動翻譯",
|
||||
"settingsHideBottomNav": "隱藏底部導航",
|
||||
"settingsSoundEffects": "音效",
|
||||
"settingsAprilFoolFeatures": "愚人節功能",
|
||||
"settingsEnterToSend": "按下 Enter 發送",
|
||||
"settingsTransparentAppBar": "使用完全透明的狀態欄",
|
||||
"settingsCustomFonts": "自定義字體",
|
||||
@@ -682,9 +681,9 @@
|
||||
"articleAttachmentHint": "附件必須上傳並插入到文章主體中才能顯示出來。",
|
||||
"postVisibility": "可見性",
|
||||
"currentMembershipMember": "恆星計劃成員 · {}",
|
||||
"membershipPriceStellar": "需要用戶等級 3+,每月價格 1200 NSP",
|
||||
"membershipPriceNova": "需要用戶等級 6+,每月價格 2400 NSP",
|
||||
"membershipPriceSupernova": "需要用戶等級 9+,每月價格 3600 NSP",
|
||||
"membershipPriceStellar": "需要用戶等級 20+,每月價格 1200 NSP",
|
||||
"membershipPriceNova": "需要用戶等級 40+,每月價格 2400 NSP",
|
||||
"membershipPriceSupernova": "需要用戶等級 60+,每月價格 3600 NSP",
|
||||
"sharePostPhoto": "通過圖片分享帖子",
|
||||
"wouldYouLikeToNavigateToChat": "你想要前往聊天頁面嗎?",
|
||||
"abuseReports": "舉報",
|
||||
@@ -1060,7 +1059,7 @@
|
||||
"failedToDeleteRecycledFiles": "已回收檔案刪除失敗",
|
||||
"upload": "上傳",
|
||||
"deleteMessage": "刪除訊息",
|
||||
"deleteMessageConfirmation": "確定要刪除此郵件嗎?",
|
||||
"deleteMessageConfirmation": "確定要刪除此郵件嗎?",
|
||||
"customReaction": "自訂反應",
|
||||
"customReactions": "自訂反應",
|
||||
"stickerPlaceholder": "貼紙佔位符",
|
||||
@@ -1131,348 +1130,417 @@
|
||||
"noReceivedGifts": "没有收到过礼物",
|
||||
"stellarGift": "恆星禮物",
|
||||
"novaGift": "新星禮物",
|
||||
"supernovaGift": "Supernova Gift",
|
||||
"sameAsMembership": "Same as membership",
|
||||
"enterGiftCodeToRedeem": "Enter gift code to redeem",
|
||||
"enterGiftCode": "Enter gift code",
|
||||
"giftPurchased": "Gift Purchased!",
|
||||
"shareCodeWithRecipient": "Share this code with the recipient to redeem the gift.",
|
||||
"openGiftAnyoneCanRedeem": "This is an open gift that anyone can redeem.",
|
||||
"ok": "OK",
|
||||
"selectedRecipient": "Selected recipient",
|
||||
"noRecipientSelected": "No recipient selected",
|
||||
"thisWillBeAnOpenGift": "This will be an open gift",
|
||||
"personalMessage": "Personal Message",
|
||||
"addPersonalMessageForRecipient": "Add a personal message for the recipient",
|
||||
"giftStatusCreated": "Created",
|
||||
"giftStatusSent": "Sent",
|
||||
"giftStatusRedeemed": "Redeemed",
|
||||
"giftStatusCancelled": "Cancelled",
|
||||
"giftStatusExpired": "Expired",
|
||||
"giftStatusUnknown": "Unknown",
|
||||
"giftCodeCopiedToClipboard": "Gift code copied to clipboard",
|
||||
"codeLabel": "Code: ",
|
||||
"subscriptionLabel": "Subscription: ",
|
||||
"toLabel": "To: ",
|
||||
"fromLabel": "From: ",
|
||||
"messageLabel": "Message: ",
|
||||
"giftRedeemed": "Gift Redeemed!",
|
||||
"giftRedeemedSuccessfully": "You have successfully redeemed the gift. Your new subscription is now active.",
|
||||
"cancelGift": "Cancel Gift",
|
||||
"cancelGiftConfirm": "Are you sure you want to cancel this gift? This action cannot be undone.",
|
||||
"giftCancelledSuccessfully": "Gift cancelled successfully",
|
||||
"createFund": "Create Fund",
|
||||
"fundAmount": "Fund Amount",
|
||||
"enterAmount": "Enter Amount",
|
||||
"selectCurrency": "Select Currency",
|
||||
"splitType": "Split Type",
|
||||
"evenSplit": "Even Split",
|
||||
"equalAmountEach": "Equal amount for each recipient",
|
||||
"randomSplit": "Random Split",
|
||||
"randomAmountEach": "Random amount for each recipient",
|
||||
"recipientCount": "Recipient Count",
|
||||
"numberOfRecipients": "Number of Recipients",
|
||||
"addPersonalMessageForRecipients": "Add a personal message for recipients",
|
||||
"invalidAmount": "Invalid amount",
|
||||
"invalidRecipientCount": "Invalid recipient count",
|
||||
"fundOverview": "Fund Overview",
|
||||
"totalFundsSent": "Total Funds Sent",
|
||||
"totalFundsReceived": "Total Funds Received",
|
||||
"transactions": "Transactions",
|
||||
"myFunds": "My Funds",
|
||||
"availableFunds": "Available Funds",
|
||||
"fundStatusCreated": "Created",
|
||||
"fundStatusPartial": "Partially Claimed",
|
||||
"fundStatusCompleted": "Fully Claimed",
|
||||
"fundStatusExpired": "Expired",
|
||||
"fundStatusUnknown": "Unknown",
|
||||
"recipients": "Recipients",
|
||||
"fundClaimedSuccessfully": "Fund claimed successfully!",
|
||||
"claim": "Claim",
|
||||
"noFundsCreated": "No funds created yet",
|
||||
"createYourFirstFund": "Create your first fund to get started",
|
||||
"noAvailableFunds": "No available funds",
|
||||
"fundsWillAppearHere": "Funds you can claim will appear here",
|
||||
"fundCreatedSuccessfully": "Fund created successfully!",
|
||||
"selectRecipients": "Select Recipients",
|
||||
"noRecipientsSelected": "No recipients selected",
|
||||
"selectRecipientsToSendFund": "Select recipients to send the fund to",
|
||||
"addRecipient": "Add Recipient",
|
||||
"addMoreRecipients": "Add More Recipients",
|
||||
"transactionDetails": "Transaction Details",
|
||||
"remarks": "Remarks",
|
||||
"payer": "Payer",
|
||||
"payee": "Payee",
|
||||
"transactionType": "Transaction Type",
|
||||
"transfer": "Transfer",
|
||||
"payment": "Payment",
|
||||
"systemWallet": "System Wallet",
|
||||
"date": "Date",
|
||||
"createTransfer": "Create Transfer",
|
||||
"transferAmount": "Transfer Amount",
|
||||
"selectPayee": "Select Payee",
|
||||
"selectedPayee": "Selected Payee",
|
||||
"noPayeeSelected": "No payee selected",
|
||||
"selectPayeeToTransfer": "Select payee to transfer to",
|
||||
"addRemark": "Add Remark",
|
||||
"transferRemark": "Transfer Remark",
|
||||
"addRemarkForTransfer": "Add remark for transfer",
|
||||
"enterPinToConfirmTransfer": "Enter your 6-digit PIN to confirm transfer",
|
||||
"transferCreatedSuccessfully": "Transfer created successfully!",
|
||||
"postUpdate": "Update",
|
||||
"fileMetadata": "File Metadata",
|
||||
"resend": "Resend",
|
||||
"fileInfoTitle": "File Information",
|
||||
"download": "Download",
|
||||
"info": "Info",
|
||||
"noStickers": "No Stickers",
|
||||
"noStickersInPack": "This pack does not contains stickers",
|
||||
"noStickerPacks": "No Sticker Packs",
|
||||
"refresh": "Refresh",
|
||||
"spoiler": "Spoiler",
|
||||
"activityHeatmap": "Activity Heatmap",
|
||||
"custom": "Custom",
|
||||
"usernameColor": "Username Color",
|
||||
"colorType": "Color Type",
|
||||
"plain": "Plain",
|
||||
"gradient": "Gradient",
|
||||
"colorValue": "Color Value",
|
||||
"gradientDirection": "Gradient Direction",
|
||||
"gradientDirectionToRight": "To Right",
|
||||
"gradientDirectionToLeft": "To Left",
|
||||
"gradientDirectionToBottom": "To Bottom",
|
||||
"gradientDirectionToTop": "To Top",
|
||||
"gradientDirectionToBottomRight": "To Bottom Right",
|
||||
"gradientDirectionToBottomLeft": "To Bottom Left",
|
||||
"gradientDirectionToTopRight": "To Top Right",
|
||||
"gradientDirectionToTopLeft": "To Top Left",
|
||||
"gradientColors": "Gradient Colors",
|
||||
"color": "Color",
|
||||
"addColor": "Add Color",
|
||||
"availableWithYourPlan": "Available with your plan",
|
||||
"upgradeRequired": "Upgrade required",
|
||||
"settingsDisableAnimation": "Disable Animation",
|
||||
"addTag": "Add Tag",
|
||||
"supernovaGift": "超新星訂閱",
|
||||
"sameAsMembership": "於成員相同",
|
||||
"enterGiftCodeToRedeem": "輸入禮物程式碼以兌換",
|
||||
"enterGiftCode": "輸入禮物程式碼",
|
||||
"giftPurchased": "已購買禮物!",
|
||||
"shareCodeWithRecipient": "與收件人分享此程式碼來兌換禮物。",
|
||||
"openGiftAnyoneCanRedeem": "這是一份任何人都可以兌換的公開禮物。",
|
||||
"ok": "好的",
|
||||
"selectedRecipient": "選擇接收者",
|
||||
"noRecipientSelected": "沒有選中的接受者",
|
||||
"thisWillBeAnOpenGift": "這將是一份公開的禮物",
|
||||
"personalMessage": "個人信息",
|
||||
"addPersonalMessageForRecipient": "為收件人添加個人訊息",
|
||||
"giftStatusCreated": "已創建",
|
||||
"giftStatusSent": "發送",
|
||||
"giftStatusRedeemed": "已兌換",
|
||||
"giftStatusCancelled": "已取消",
|
||||
"giftStatusExpired": "已過期",
|
||||
"giftStatusUnknown": "未知",
|
||||
"giftCodeCopiedToClipboard": "禮物程式碼已經複製到剪貼簿",
|
||||
"codeLabel": "程式碼:",
|
||||
"subscriptionLabel": "訂閱:",
|
||||
"toLabel": "至:",
|
||||
"fromLabel": "從:",
|
||||
"messageLabel": "消息:",
|
||||
"giftRedeemed": "禮物已兌換!",
|
||||
"giftRedeemedSuccessfully": "您已成功兌換了禮物。您的新訂閱現在已經生效。",
|
||||
"cancelGift": "取消禮物",
|
||||
"cancelGiftConfirm": "您確定要取消此禮物?此操作無法撤銷。",
|
||||
"giftCancelledSuccessfully": "禮物成功取消",
|
||||
"createFund": "創建支票",
|
||||
"fundAmount": "支票金額",
|
||||
"enterAmount": "輸入金額",
|
||||
"selectCurrency": "選擇貨幣",
|
||||
"splitType": "拆分類型",
|
||||
"evenSplit": "平均拆分",
|
||||
"equalAmountEach": "每個收款人的金額相同",
|
||||
"randomSplit": "隨機拆分",
|
||||
"randomAmountEach": "每個收款人的金額隨機",
|
||||
"recipientCount": "收款人總計",
|
||||
"numberOfRecipients": "收款人數量",
|
||||
"addPersonalMessageForRecipients": "為收款人添加個人信息",
|
||||
"invalidAmount": "無效的金額",
|
||||
"invalidRecipientCount": "收款人數量無效",
|
||||
"fundOverview": "支票概覽",
|
||||
"totalFundsSent": "共發送支票",
|
||||
"totalFundsReceived": "共領取支票",
|
||||
"transactions": "交易",
|
||||
"myFunds": "我的支票",
|
||||
"availableFunds": "可用支票",
|
||||
"fundStatusCreated": "已創建",
|
||||
"fundStatusPartial": "部分領取",
|
||||
"fundStatusCompleted": "已領完",
|
||||
"fundStatusExpired": "已過期",
|
||||
"fundStatusUnknown": "未知",
|
||||
"recipients": "收款人",
|
||||
"fundClaimedSuccessfully": "支票成功領取!",
|
||||
"claim": "領取",
|
||||
"noFundsCreated": "還沒有創建的支票",
|
||||
"createYourFirstFund": "創建您的第一個支票以開始",
|
||||
"noAvailableFunds": "暫無可用支票",
|
||||
"fundsWillAppearHere": "您可以領取的支票將出現在這裡",
|
||||
"fundCreatedSuccessfully": "支票成功創建!",
|
||||
"selectRecipients": "選擇收款人",
|
||||
"noRecipientsSelected": "沒有選擇收款人",
|
||||
"selectRecipientsToSendFund": "選擇收款人將支票發送到",
|
||||
"addRecipient": "添加收款人",
|
||||
"addMoreRecipients": "添加更多收款人",
|
||||
"transactionDetails": "交易詳情",
|
||||
"remarks": "備註",
|
||||
"payer": "付款方",
|
||||
"payee": "交易方",
|
||||
"transactionType": "交易類型",
|
||||
"transfer": "轉帳",
|
||||
"payment": "支付",
|
||||
"systemWallet": "系統錢包",
|
||||
"date": "日期",
|
||||
"createTransfer": "創建交易",
|
||||
"transferAmount": "交易金額",
|
||||
"selectPayee": "請選擇收款人",
|
||||
"selectedPayee": "選定的收款人",
|
||||
"noPayeeSelected": "沒有選擇收款人",
|
||||
"selectPayeeToTransfer": "選擇要轉帳的收款人",
|
||||
"addRemark": "添加備註",
|
||||
"transferRemark": "交易備註",
|
||||
"addRemarkForTransfer": "為轉帳添加備註",
|
||||
"enterPinToConfirmTransfer": "輸入您的 6 位PIN碼以確認轉帳",
|
||||
"transferCreatedSuccessfully": "轉帳成功創建",
|
||||
"postUpdate": "更新",
|
||||
"fileMetadata": "檔案資訊",
|
||||
"resend": "重新發送",
|
||||
"fileInfoTitle": "檔案信息",
|
||||
"download": "下載",
|
||||
"info": "信息",
|
||||
"noStickers": "沒有貼圖",
|
||||
"noStickersInPack": "這個包不包含貼圖",
|
||||
"noStickerPacks": "沒有貼圖包",
|
||||
"refresh": "刷新",
|
||||
"spoiler": "已隱藏",
|
||||
"activityHeatmap": "活动热力图",
|
||||
"custom": "自定義",
|
||||
"usernameColor": "用戶名顏色",
|
||||
"colorType": "顏色類型",
|
||||
"plain": "純色",
|
||||
"gradient": "漸變",
|
||||
"colorValue": "色值",
|
||||
"gradientDirection": "漸變方向",
|
||||
"gradientDirectionToRight": "向右",
|
||||
"gradientDirectionToLeft": "向左",
|
||||
"gradientDirectionToBottom": "向底部",
|
||||
"gradientDirectionToTop": "向上",
|
||||
"gradientDirectionToBottomRight": "向右下角",
|
||||
"gradientDirectionToBottomLeft": "向左下角",
|
||||
"gradientDirectionToTopRight": "向右上角",
|
||||
"gradientDirectionToTopLeft": "向左下角",
|
||||
"gradientColors": "漸變顏色",
|
||||
"color": "顏色",
|
||||
"addColor": "添加顏色",
|
||||
"availableWithYourPlan": "隨您的方案提供",
|
||||
"upgradeRequired": "需要升級",
|
||||
"settingsDisableAnimation": "停用動畫",
|
||||
"addTag": "添加標籤",
|
||||
"accountConnectionProviderSpotify": "Spotify",
|
||||
"accountConnectionProviderSteam": "Steam",
|
||||
"timezoneNotFound": "Time zone not found",
|
||||
"awardPoints": "Awarded {} points",
|
||||
"postFeaturedOn": "Post featured on {}",
|
||||
"messageSentAt": "Sent at {}",
|
||||
"myTickets": "My Tickets",
|
||||
"drawHistory": "Draw History",
|
||||
"lottery": "Lottery",
|
||||
"noLotteryTickets": "No lottery tickets yet",
|
||||
"buyYourFirstTicket": "Buy your first lottery ticket to get started!",
|
||||
"buyTicket": "Buy Ticket",
|
||||
"ticketNumbers": "Numbers: {}, Special: {}",
|
||||
"cost": "Cost",
|
||||
"multiplier": "Multiplier",
|
||||
"prizeWon": "Prize Won",
|
||||
"pending": "Pending",
|
||||
"drawn": "Drawn",
|
||||
"won": "Won",
|
||||
"lost": "Lost",
|
||||
"noDrawHistory": "No draw history yet",
|
||||
"buyLotteryTicket": "Buy Lottery Ticket",
|
||||
"selectNumbers": "Select Numbers",
|
||||
"select5UniqueNumbers": "Select 5 unique numbers",
|
||||
"selectSpecialNumber": "Select Special Number",
|
||||
"selectMultiplier": "Select Multiplier",
|
||||
"baseCost": "Base Cost",
|
||||
"totalCost": "Total Cost",
|
||||
"prizeStructure": "Prize Structure",
|
||||
"enterPinToConfirmPurchase": "Enter your PIN to confirm purchase",
|
||||
"ticketPurchasedSuccessfully": "Ticket purchased successfully!",
|
||||
"winningNumbers": "Winning Numbers",
|
||||
"specialNumber": "Special Number",
|
||||
"totalTickets": "Total Tickets",
|
||||
"totalWinners": "Total Winners",
|
||||
"prizePool": "Prize Pool",
|
||||
"enterPinToConfirmPayment": "Enter your PIN code to confirm payment",
|
||||
"purchase": "Purchase",
|
||||
"multiplierLabel": "Multiplier",
|
||||
"specialOnly": "Special Only",
|
||||
"matches": "Matches",
|
||||
"thoughtDefaultTopic": "Reflection",
|
||||
"thoughtAiName": "SN-chan",
|
||||
"thoughtUserName": "You",
|
||||
"thoughtStreamingHint": "Sn-chan is thinking...",
|
||||
"thoughtInputHint": "Ask sn-chan anything...",
|
||||
"thoughtNewConversation": "Start New Conversation",
|
||||
"thoughtParseError": "Failed to parse AI response",
|
||||
"thoughtFunctionCall": "Use {}",
|
||||
"aiThought": "AI Thought",
|
||||
"aiThoughtTitle": "Let sn-chan think",
|
||||
"postReferenceUnavailable": "Referenced post is unavailable",
|
||||
"fabLocation": "FAB Location",
|
||||
"activities": "Activities",
|
||||
"presenceTypeGaming": "Playing",
|
||||
"presenceTypeMusic": "Listening to Music",
|
||||
"presenceTypeWorkout": "Working out",
|
||||
"articleCompose": "Compose Article",
|
||||
"backToHub": "Back to Hub",
|
||||
"advancedFilters": "Advanced Filters",
|
||||
"searchPosts": "Search Posts",
|
||||
"sortBy": "Sort by",
|
||||
"fromDate": "From Date",
|
||||
"toDate": "To Date",
|
||||
"popularity": "Popularity",
|
||||
"descendingOrder": "Descending Order",
|
||||
"selectDate": "Select Date",
|
||||
"pinnedPosts": "Pinned Posts",
|
||||
"customReactionHint": "Custom Reaction allow you to use user uploaded stickers as the symbol of the reaction for the post. Exclusive for Stellar Program members.",
|
||||
"publicationSites": "Publication Sites",
|
||||
"uploadTasks": "Upload Tasks",
|
||||
"thoughtFunctionCallBegin": "Calling tool {}",
|
||||
"thoughtFunctionCallFinish": "{} responded",
|
||||
"thoughtUnpaidHint": "Thinking unavaiable due to unpaid orders",
|
||||
"more": "More",
|
||||
"collapse": "Collapse",
|
||||
"pollConfirmDiscard": "Are you sure you want to leave? All the poll data you're editing will not be saved.",
|
||||
"timezoneNotFound": "找不到時區",
|
||||
"awardPoints": "獎賞 {} 點",
|
||||
"postFeaturedOn": "帖文在 {} 被精選",
|
||||
"messageSentAt": "發送在 {}",
|
||||
"myTickets": "我的彩票",
|
||||
"drawHistory": "開獎歷史",
|
||||
"lottery": "彩票",
|
||||
"noLotteryTickets": "還沒有彩票",
|
||||
"buyYourFirstTicket": "購買您的第一張彩票以開始!",
|
||||
"buyTicket": "買彩票",
|
||||
"ticketNumbers": "數字:{},特殊數字:{}",
|
||||
"cost": "花費",
|
||||
"multiplier": "倍率",
|
||||
"prizeWon": "獲勝者",
|
||||
"pending": "待開獎",
|
||||
"drawn": "已開獎",
|
||||
"won": "獲勝",
|
||||
"lost": "失敗",
|
||||
"noDrawHistory": "還沒有開獎曆史",
|
||||
"buyLotteryTicket": "購買彩票",
|
||||
"selectNumbers": "選擇數字",
|
||||
"select5UniqueNumbers": "選擇 5 個不同的數字",
|
||||
"selectSpecialNumber": "選擇特殊數字",
|
||||
"selectMultiplier": "選擇倍率",
|
||||
"baseCost": "基礎花費",
|
||||
"totalCost": "總費用",
|
||||
"prizeStructure": "獎金分級",
|
||||
"enterPinToConfirmPurchase": "輸入您的 PIN 碼以確認購買",
|
||||
"ticketPurchasedSuccessfully": "彩票購買成功!",
|
||||
"winningNumbers": "獲勝數字",
|
||||
"specialNumber": "特殊數字",
|
||||
"totalTickets": "總售出票數",
|
||||
"totalWinners": "總中獎者",
|
||||
"prizePool": "獎池",
|
||||
"enterPinToConfirmPayment": "輸入您的 PIN 碼以確認交易",
|
||||
"purchase": "購買",
|
||||
"multiplierLabel": "倍率",
|
||||
"specialOnly": "僅特殊數字",
|
||||
"matches": "場次",
|
||||
"thoughtDefaultTopic": "尋思",
|
||||
"thoughtAiName": "SN醬",
|
||||
"thoughtUserName": "你",
|
||||
"thoughtStreamingHint": "SN醬正在思考……",
|
||||
"thoughtInputHint": "問SN醬一些東西……",
|
||||
"thoughtNewConversation": "開始新對話",
|
||||
"thoughtParseError": "解析 AI 響應失敗",
|
||||
"thoughtFunctionCall": "使用 {}",
|
||||
"aiThought": "尋思",
|
||||
"aiThoughtTitle": "讓SN醬思考",
|
||||
"postReferenceUnavailable": "應用的帖子不可用",
|
||||
"fabLocation": "底部菜單按鈕位置",
|
||||
"activities": "活動",
|
||||
"presenceTypeGaming": "正在玩",
|
||||
"presenceTypeMusic": "正在聽音樂",
|
||||
"presenceTypeWorkout": "鍛煉中",
|
||||
"articleCompose": "撰寫文章",
|
||||
"backToHub": "返回至主頁",
|
||||
"advancedFilters": "高級篩選",
|
||||
"searchPosts": "搜索帖子",
|
||||
"sortBy": "排序方式",
|
||||
"fromDate": "起始日期",
|
||||
"toDate": "截止日期",
|
||||
"popularity": "按熱度",
|
||||
"descendingOrder": "降序排序",
|
||||
"selectDate": "選擇日期",
|
||||
"pinnedPosts": "已置頂的帖子",
|
||||
"customReactionHint": "自訂反應允許你使用用戶上傳貼紙作為帖子反應的符號,需要恆星計劃訂閱。",
|
||||
"publicationSites": "發佈者網站",
|
||||
"uploadTasks": "上傳任務",
|
||||
"thoughtFunctionCallBegin": "調用工具 {}",
|
||||
"thoughtFunctionCallFinish": "工具 {}",
|
||||
"thoughtUnpaidHint": "尋思因為有未支付的訂單而被禁用",
|
||||
"more": "更多",
|
||||
"collapse": "折疊",
|
||||
"pollConfirmDiscard": "您確定要離開嗎?您編輯的所有資料都不會被保存。",
|
||||
"discard": "Discard",
|
||||
"fund": "Fund",
|
||||
"fundsRecent": "Recent Funds",
|
||||
"fundCreateNew": "Create New",
|
||||
"fundCreateNewHint": "Create a new fund for your message. Select recipients and amount.",
|
||||
"amountOfSplits": "Amount of Splits",
|
||||
"enterNumberOfSplits": "Enter Splits Amount",
|
||||
"orCreateWith": "Or\ncreate with",
|
||||
"unindexedFiles": "Unindexed files",
|
||||
"folder": "Folder",
|
||||
"clearCompleted": "Clear Completed",
|
||||
"uploadSuccess": "Upload successful!",
|
||||
"wouldYouLikeToViewFile": "Would you like to view the file?",
|
||||
"contentCantEmpty": "Content cannot be empty",
|
||||
"features": "Features",
|
||||
"unnamed": "Unnamed",
|
||||
"fundEnvelopeLoadFailed": "Failed to load fund envelope",
|
||||
"fundEnvelope": "Fund Envelope",
|
||||
"fundEnvelopeRemaining": "Remaining: {} {}",
|
||||
"fundEnvelopeSplit": "Split: {}",
|
||||
"fundEnvelopeSplitEvenly": "Evenly",
|
||||
"fundEnvelopeSplitRandomly": "Randomly",
|
||||
"fundEnvelopeClaimSuccess": "Fund claimed successfully!",
|
||||
"fundEnvelopeStatusCreated": "Created",
|
||||
"fundEnvelopeStatusPartial": "Partially Claimed",
|
||||
"fundEnvelopeStatusCompleted": "Fully Claimed",
|
||||
"fundEnvelopeStatusExpired": "Expired",
|
||||
"fundEnvelopeStatusUnknown": "Unknown",
|
||||
"fundEnvelopeRecipients": "Recipients ({}/{} claimed)",
|
||||
"fund": "支票",
|
||||
"fundsRecent": "最近的支票",
|
||||
"fundCreateNew": "創建新的",
|
||||
"fundCreateNewHint": "為您的消息創建一個新的紅包。選擇接收者和金額。",
|
||||
"amountOfSplits": "份數",
|
||||
"enterNumberOfSplits": "單份金額",
|
||||
"orCreateWith": "或\n使用第三方賬戶登錄",
|
||||
"unindexedFiles": "未索引的檔案",
|
||||
"folder": "文件夾",
|
||||
"clearCompleted": "清除已經完成的",
|
||||
"uploadSuccess": "上傳成功!",
|
||||
"wouldYouLikeToViewFile": "您想查看檔案嗎?",
|
||||
"contentCantEmpty": "內容不能為空",
|
||||
"features": "功能",
|
||||
"unnamed": "未命名",
|
||||
"fundEnvelopeLoadFailed": "載入支票信封失敗",
|
||||
"fundEnvelope": "支票信封",
|
||||
"fundEnvelopeRemaining": "剩餘:{} {}",
|
||||
"fundEnvelopeSplit": "拆分:{}",
|
||||
"fundEnvelopeSplitEvenly": "均分",
|
||||
"fundEnvelopeSplitRandomly": "隨機",
|
||||
"fundEnvelopeClaimSuccess": "支票領取成功!",
|
||||
"fundEnvelopeStatusCreated": "已創建",
|
||||
"fundEnvelopeStatusPartial": "已領取部分",
|
||||
"fundEnvelopeStatusCompleted": "已全部領取",
|
||||
"fundEnvelopeStatusExpired": "已過期",
|
||||
"fundEnvelopeStatusUnknown": "未知",
|
||||
"fundEnvelopeRecipients": "收款人 ({}/{}已領取)",
|
||||
"fundEnvelopeExpiredDaysAgo": {
|
||||
"one": "Expired {} day ago",
|
||||
"other": "Expired {} days ago"
|
||||
"one": "{}天前過期",
|
||||
"other": "{}天前過期"
|
||||
},
|
||||
"fundEnvelopeExpiresSoon": "Expires soon",
|
||||
"fundEnvelopeExpiresSoon": "即將過期",
|
||||
"fundEnvelopeExpiresInHours": {
|
||||
"one": "Expires in {} hour",
|
||||
"other": "Expires in {} hours"
|
||||
"one": "{}小時後過期",
|
||||
"other": "{}小時後過期"
|
||||
},
|
||||
"fundEnvelopeExpiresInDays": {
|
||||
"one": "Expires in {} day",
|
||||
"other": "Expires in {} days"
|
||||
"one": "{}天後過期",
|
||||
"other": "{}天後過期"
|
||||
},
|
||||
"fundEnvelopeRemainingWithSplits": "{} {} / {} splits",
|
||||
"fundEnvelopeUnknownUser": "Unknown User",
|
||||
"deleteSite": "Delete Site",
|
||||
"deleteSiteConfirm": "Are you sure you want to delete this site?",
|
||||
"siteDeletedSuccess": "Site deleted successfully",
|
||||
"siteSlug": "Slug",
|
||||
"siteSlugHint": "my-site",
|
||||
"siteSlugRequired": "Please enter a slug",
|
||||
"siteSlugInvalid": "Slug can only contain lowercase letters, numbers, and dashes",
|
||||
"siteName": "Site Name",
|
||||
"siteNameHint": "My Publication Site",
|
||||
"siteNameRequired": "Please enter a site name",
|
||||
"siteMode": "Mode",
|
||||
"siteModeFullyManaged": "Fully Managed",
|
||||
"siteModeSelfManaged": "Self-Managed",
|
||||
"editPublicationSite": "Edit Publication Site",
|
||||
"deletePublicationSite": "Delete Publication Site",
|
||||
"publicationSiteSavedSuccess": "Publication site saved successfully",
|
||||
"publicationSiteDeleteConfirm": "Are you sure you want to delete this publication site? This action cannot be undone.",
|
||||
"publicationSiteDeletedSuccess": "Publication site deleted successfully",
|
||||
"newPublicationSite": "New Publication Site",
|
||||
"siteDetails": "Site Details",
|
||||
"siteInformation": "Site Information",
|
||||
"siteDomain": "Domain",
|
||||
"siteCreated": "Created",
|
||||
"siteUpdated": "Updated",
|
||||
"failedToLoadSite": "Failed to load site",
|
||||
"sitePages": "Pages",
|
||||
"noPagesYet": "No pages yet",
|
||||
"createFirstPage": "Create your first page to get started",
|
||||
"failedToLoadPages": "Failed to load pages",
|
||||
"fileManagement": "File Management",
|
||||
"siteFiles": "Files",
|
||||
"siteFolder": "Folder",
|
||||
"siteRoot": "Root",
|
||||
"noFilesUploadedYet": "No files uploaded yet",
|
||||
"uploadFirstFile": "Upload your first file to get started",
|
||||
"failedToLoadFiles": "Failed to load files",
|
||||
"noFilesFoundInFolder": "No files found in the selected folder",
|
||||
"fileActions": "File Actions",
|
||||
"purgeFiles": "Purge Files",
|
||||
"purgeFilesDescription": "Remove all uploaded files from the site",
|
||||
"deploySite": "Deploy Site",
|
||||
"deploySiteDescription": "Upload and deploy a new version from ZIP archive",
|
||||
"confirmPurge": "Confirm Purge",
|
||||
"purgeFilesConfirm": "This will permanently delete all files uploaded to this site. This action cannot be undone. Are you sure you want to continue?",
|
||||
"purgeAllFiles": "Purge All Files",
|
||||
"allFilesPurgedSuccess": "All files purged successfully",
|
||||
"failedToPurgeFiles": "Failed to purge files: {}",
|
||||
"siteDeployedSuccess": "Site deployed successfully",
|
||||
"failedToDeploySite": "Failed to deploy site: {}",
|
||||
"createPage": "Create Page",
|
||||
"editPage": "Edit Page",
|
||||
"pageType": "Page Type",
|
||||
"htmlPage": "HTML Page",
|
||||
"redirectPage": "Redirect Page",
|
||||
"pageTypeRequired": "Please select a page type",
|
||||
"pagePath": "Page Path",
|
||||
"pagePathHint": "/about, /contact, etc.",
|
||||
"pagePathRequired": "Please enter a page path",
|
||||
"pagePathInvalid": "Page path can only contain letters, numbers, hyphens, underscores, and slashes",
|
||||
"pagePathMustStartWithSlash": "Page path must start with /",
|
||||
"pagePathNoConsecutiveSlashes": "Page path cannot have consecutive slashes",
|
||||
"pageTitle": "Page Title",
|
||||
"pageTitleHint": "About Us, Contact, etc.",
|
||||
"pageTitleRequired": "Please enter a page title",
|
||||
"pageContentHtml": "Page Content (HTML)",
|
||||
"pageContentHint": "<h1>Hello World</h1><p>This is my page content...</p>",
|
||||
"pageContentRequired": "Please enter HTML content for the page",
|
||||
"redirectTarget": "Redirect Target",
|
||||
"redirectTargetHint": "/new-page, https://example.com, etc.",
|
||||
"redirectTargetRequired": "Please enter a redirect target",
|
||||
"redirectTargetInvalid": "Target must be a relative path (/) or absolute URL (http/https)",
|
||||
"deletePage": "Delete Page",
|
||||
"deletePageConfirm": "Are you sure you want to delete this page?",
|
||||
"savePage": "Save Page",
|
||||
"pageCreatedSuccess": "Page created successfully",
|
||||
"pageUpdatedSuccess": "Page updated successfully",
|
||||
"pageDeletedSuccess": "Page deleted successfully",
|
||||
"uploadFiles": "Upload Files",
|
||||
"uploadPath": "Upload Path",
|
||||
"uploadPathHint": "/ (root) or /assets/images/",
|
||||
"uploadPathRequired": "Please enter an upload path",
|
||||
"uploadPathMustStartWithSlash": "Path must start with /",
|
||||
"uploadPathNoSpaces": "Path cannot contain spaces",
|
||||
"uploadPathNoConsecutiveSlashes": "Path cannot have consecutive slashes",
|
||||
"percentCompleted": "{}% completed",
|
||||
"filesToUpload": "{} files to upload",
|
||||
"fileSizeKb": "Size: {} KB",
|
||||
"uploadingEllipsis": "Uploading...",
|
||||
"fundEnvelopeRemainingWithSplits": "{} {} / {} 份",
|
||||
"fundEnvelopeUnknownUser": "未知用戶",
|
||||
"deleteSite": "刪除網站",
|
||||
"deleteSiteConfirm": "您確定要刪除此網站嗎?",
|
||||
"siteDeletedSuccess": "網站成功刪除",
|
||||
"siteSlug": "標識符",
|
||||
"siteSlugHint": "我的站點",
|
||||
"siteSlugRequired": "請輸入一個標識符",
|
||||
"siteSlugInvalid": "標識符只能包含小寫字母、數字和連字符",
|
||||
"siteName": "網站名稱",
|
||||
"siteNameHint": "我的發佈者網站",
|
||||
"siteNameRequired": "請輸入一個站點名稱",
|
||||
"siteMode": "模式",
|
||||
"siteModeFullyManaged": "全託管",
|
||||
"siteModeSelfManaged": "自託管",
|
||||
"editPublicationSite": "編輯發佈者網站",
|
||||
"deletePublicationSite": "刪除發佈者網站",
|
||||
"publicationSiteSavedSuccess": "發佈者網站保存成功",
|
||||
"publicationSiteDeleteConfirm": "您確定要刪除此發佈者網站嗎?此操作不能撤銷。",
|
||||
"publicationSiteDeletedSuccess": "發佈者網站成功刪除",
|
||||
"newPublicationSite": "新建發佈者網站",
|
||||
"siteDetails": "網站描述",
|
||||
"siteInformation": "網站信息",
|
||||
"siteDomain": "域名",
|
||||
"siteCreated": "創建于",
|
||||
"siteUpdated": "更新于",
|
||||
"failedToLoadSite": "加載網站失敗",
|
||||
"sitePages": "頁面",
|
||||
"noPagesYet": "還沒有頁面",
|
||||
"createFirstPage": "創建您的第一個頁面以開始",
|
||||
"failedToLoadPages": "加載頁面失敗",
|
||||
"fileManagement": "檔案管理器",
|
||||
"siteFiles": "檔案",
|
||||
"siteFolder": "資料夾",
|
||||
"siteRoot": "根",
|
||||
"noFilesUploadedYet": "尚未上傳任何檔案",
|
||||
"uploadFirstFile": "上傳您的第一個檔案以開始",
|
||||
"failedToLoadFiles": "加載檔案失敗",
|
||||
"noFilesFoundInFolder": "在選擇的資料夾中沒有檔案",
|
||||
"fileActions": "檔案選項",
|
||||
"purgeFiles": "清除檔案",
|
||||
"purgeFilesDescription": "從這個網站刪除全部文件",
|
||||
"deploySite": "部署網站",
|
||||
"deploySiteDescription": "從ZIP存檔上傳和部署新版本",
|
||||
"confirmPurge": "確認清空",
|
||||
"purgeFilesConfirm": "這將永久刪除上傳到本網站的所有檔案。此操作無法復原。您確定要繼續嗎?",
|
||||
"purgeAllFiles": "清除所有文檔案",
|
||||
"allFilesPurgedSuccess": "全部檔案成功清空",
|
||||
"failedToPurgeFiles": "清除檔案失敗:{}",
|
||||
"siteDeployedSuccess": "網站成功部署",
|
||||
"failedToDeploySite": "部署網站失敗:{}",
|
||||
"createPage": "創建頁面",
|
||||
"editPage": "編輯頁面",
|
||||
"pageType": "頁面類型",
|
||||
"htmlPage": "HTML 頁面",
|
||||
"redirectPage": "重定向頁面",
|
||||
"pageTypeRequired": "請選擇一個頁面類型",
|
||||
"pagePath": "頁面路徑",
|
||||
"pagePathHint": "例如/about,/contact等",
|
||||
"pagePathRequired": "請輸入一個頁面路徑",
|
||||
"pagePathInvalid": "頁面路徑只能包含字母、數字、連字符、底線和斜線",
|
||||
"pagePathMustStartWithSlash": "頁面路徑以/開始",
|
||||
"pagePathNoConsecutiveSlashes": "頁面路徑不能有連續的斜線",
|
||||
"pageTitle": "頁面標題",
|
||||
"pageTitleHint": "例如About Us,Contact等",
|
||||
"pageTitleRequired": "請輸入一個頁面標題",
|
||||
"pageContentHtml": "頁面內容(HTML)",
|
||||
"pageContentHint": "<h1> Hello World</h1><p>這是我的頁面內容…</p>",
|
||||
"pageContentRequired": "請為頁面輸入HTML內容",
|
||||
"redirectTarget": "重定向目標",
|
||||
"redirectTargetHint": "例如/new-page,https://example.com等",
|
||||
"redirectTargetRequired": "請輸入一個重定向目標",
|
||||
"redirectTargetInvalid": "目標必須是相對路徑(/)或絕對 URL(http/https)",
|
||||
"deletePage": "刪除頁面",
|
||||
"deletePageConfirm": "您確定要刪除此頁面嗎?",
|
||||
"savePage": "保存頁面",
|
||||
"pageCreatedSuccess": "頁面創建成功",
|
||||
"pageUpdatedSuccess": "頁面更新成功",
|
||||
"pageDeletedSuccess": "頁面刪除成功",
|
||||
"uploadFiles": "上傳檔案",
|
||||
"uploadPath": "上傳路徑",
|
||||
"uploadPathHint": "/ (根目錄) 或 /assets/images/",
|
||||
"uploadPathRequired": "請輸入一個上傳路徑",
|
||||
"uploadPathMustStartWithSlash": "路徑以/開始",
|
||||
"uploadPathNoSpaces": "路徑不能包含空格",
|
||||
"uploadPathNoConsecutiveSlashes": "路徑不能包含連續的斜槓",
|
||||
"percentCompleted": "{}%已完成",
|
||||
"filesToUpload": "{} 個檔案要上傳",
|
||||
"fileSizeKb": "大小:{} KB",
|
||||
"uploadingEllipsis": "上傳中……",
|
||||
"uploadFilesCount": {
|
||||
"one": "Upload {} File",
|
||||
"other": "Upload {} Files"
|
||||
"one": "上傳 {} 個檔案",
|
||||
"other": "上傳 {} 個檔案"
|
||||
},
|
||||
"allUploadsCompleted": "All uploads completed",
|
||||
"someUploadsFailed": "Some uploads failed",
|
||||
"uploadingInProgress": "Uploading in progress",
|
||||
"readyToUpload": "Ready to upload",
|
||||
"allFilesUploadedSuccess": "All files uploaded successfully",
|
||||
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||
"dropToShare": "Drop to share"
|
||||
"allUploadsCompleted": "上傳全部完成",
|
||||
"someUploadsFailed": "部分上傳失敗",
|
||||
"uploadingInProgress": "正在上傳",
|
||||
"readyToUpload": "準備好上傳",
|
||||
"allFilesUploadedSuccess": "全部檔案完成上傳",
|
||||
"lotteryLastNumberSpecial": "最後一個選擇的數字將是您的特殊數字。",
|
||||
"lotteryMultiplierRequired": "請輸入一個倍率",
|
||||
"lotteryMultiplierRange": "倍率需要在1到10之間",
|
||||
"dropToShare": "拖拽以分享",
|
||||
"affiliationSpell": "Affiliation Spell",
|
||||
"affiliationSpellHint": "If you have an affiliation spell, enter it here.",
|
||||
"friendsOnline": "Friends Online",
|
||||
"createAccountAlmostThere": "Almost There",
|
||||
"createAccountAlmostThereHint": "You're one step away from joining the Solar Network! Please solve the captcha puzzle shows next.",
|
||||
"createAccountNotice": "Things you need to know before you create an account:",
|
||||
"createAccountConfirmEmail": "After your account being created, you need go to your email inbox to active your account to get permission to use all features.",
|
||||
"createAccountNoAltAccounts": "Multiple or alternative accounts are banned from the Solar Network, that will violates our terms of services.",
|
||||
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
|
||||
"createAccountProfile": "Create your profile",
|
||||
"createAccountToS": "Review Terms & Conditions",
|
||||
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
|
||||
"realmsDescription": "Manage realms you've joined.",
|
||||
"exploreDescription": "Explore contents on the Solar Network.",
|
||||
"accountDescription": "Information about your account.",
|
||||
"chatDescription": "Group Chats and Direct Messages",
|
||||
"connectionServerDown": "Unable to Connect",
|
||||
"appSettingsDescription": "Customize your app.",
|
||||
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
|
||||
"walletDescription": "Your source point wallet.",
|
||||
"relationshipsDescription": "Friends and connections.",
|
||||
"notificationsDescription": "See what's happended related to you recently.",
|
||||
"settingsFestivalFeatures": "Festival Limited Features",
|
||||
"categoriesAndTags": "Categories & Tags",
|
||||
"webArticlesStandDescription": "Explore external sites articles.",
|
||||
"aboutDescription": "Learn more about the Solar Network.",
|
||||
"abuseReportsDescription": "View and manage abuse reports.",
|
||||
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
|
||||
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
|
||||
"discoverRealmsDescription": "Discover new realms and join them.",
|
||||
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
|
||||
"levelingDescription": "See your leveling progress and history.",
|
||||
"notableDayToday": "{} is today!",
|
||||
"authSessionLogout": "Logout Session",
|
||||
"authSessionLogoutHint": "Are you sure you want to logout this session? This will terminate this specific login session.",
|
||||
"filesDescription": "Manage your files on the Solar Network Drive.",
|
||||
"postComposeDescription": "Compose a new post",
|
||||
"searchPostsDescription": "Search posts by title, content, or else.",
|
||||
"accountActivationAlert": "Activate your account",
|
||||
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
|
||||
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
|
||||
"accountActivationResend": "Resend",
|
||||
"ipAddress": "IP Address",
|
||||
"noFurtherData": "No further data",
|
||||
"searchAnything": "Search Anything...",
|
||||
"tapToViewAllNotifications": "Tap to view all notifications",
|
||||
"mostRecent": "Most Recent",
|
||||
"noNotificationsYet": "No notifications yet",
|
||||
"recentChats": "Recent Chats",
|
||||
"noFeaturedPostsAvailable": "No featured posts available",
|
||||
"searchChatsAndPages": "Search chats and pages...",
|
||||
"dashboard": "Dashboard",
|
||||
"dashboardDescription": "All your data in one place.",
|
||||
"postTagsCategories": "Post Tags and Categories",
|
||||
"postTagsCategoriesDescription": "Browse posts by category and tags.",
|
||||
"debugLogs": "Debug Logs",
|
||||
"debugLogsDescription": "View debug logs for troubleshooting.",
|
||||
"pinChatRoom": "Pin Chat Room",
|
||||
"pinChatRoomDescription": "Pin this chat room to the top.",
|
||||
"chatRoomPinned": "Chat room pinned successfully.",
|
||||
"chatRoomUnpinned": "Chat room unpinned successfully.",
|
||||
"pinnedChatRoom": "Pinned Rooms",
|
||||
"settingsGroupedChatList": "Grouped Chat List",
|
||||
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||
"settingsDashSearchEngine": "Search Engine for web",
|
||||
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||
"settingsDefaultScreen": "Default Screen",
|
||||
"notableDayChristmas": "Christmas",
|
||||
"notableDayNewYear": "New Year"
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class NotifyDelegate: UIResponder, UNUserNotificationCenterDelegate {
|
||||
}
|
||||
|
||||
let serverUrl = UserDefaults.standard.getServerUrl()
|
||||
let url = "\(serverUrl)/sphere/chat/\(metadata["room_id"] ?? "")/messages"
|
||||
let url = "\(serverUrl)/messager/chat/\(metadata["room_id"] ?? "")/messages"
|
||||
|
||||
let parameters: [String: Any?] = [
|
||||
"content": textResponse.userText,
|
||||
|
||||
@@ -261,7 +261,7 @@ class NetworkService {
|
||||
guard let baseURL = URL(string: serverUrl) else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
let url = baseURL.appendingPathComponent("/sphere/chat")
|
||||
let url = baseURL.appendingPathComponent("/messager/chat")
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "GET"
|
||||
@@ -283,7 +283,7 @@ class NetworkService {
|
||||
guard let baseURL = URL(string: serverUrl) else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
let url = baseURL.appendingPathComponent("/sphere/chat/\(identifier)")
|
||||
let url = baseURL.appendingPathComponent("/messager/chat/\(identifier)")
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "GET"
|
||||
@@ -308,7 +308,7 @@ class NetworkService {
|
||||
guard let baseURL = URL(string: serverUrl) else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
let url = baseURL.appendingPathComponent("/sphere/chat/invites")
|
||||
let url = baseURL.appendingPathComponent("/messager/chat/invites")
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "GET"
|
||||
@@ -330,7 +330,7 @@ class NetworkService {
|
||||
guard let baseURL = URL(string: serverUrl) else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/accept")
|
||||
let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/accept")
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
@@ -351,7 +351,7 @@ class NetworkService {
|
||||
guard let baseURL = URL(string: serverUrl) else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/decline")
|
||||
let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/decline")
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
@@ -375,9 +375,9 @@ class NetworkService {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
|
||||
// Try a different pattern: /sphere/chat/messages with roomId as query param
|
||||
// Try a different pattern: /messager/chat/messages with roomId as query param
|
||||
var components = URLComponents(
|
||||
url: baseURL.appendingPathComponent("/sphere/chat/\(chatRoomId)/messages"),
|
||||
url: baseURL.appendingPathComponent("/messager/chat/\(chatRoomId)/messages"),
|
||||
resolvingAgainstBaseURL: false
|
||||
)!
|
||||
var queryItems = [
|
||||
|
||||
@@ -455,7 +455,7 @@ struct ChatRoomView: View {
|
||||
]
|
||||
|
||||
// Create the URL
|
||||
guard let url = URL(string: "\(serverUrl)/sphere/chat/\(room.id)/messages") else {
|
||||
guard let url = URL(string: "\(serverUrl)/messager/chat/\(room.id)/messages") else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
|
||||
|
||||
108
lib/models/activitypub.dart
Normal file
108
lib/models/activitypub.dart
Normal file
@@ -0,0 +1,108 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'activitypub.freezed.dart';
|
||||
part 'activitypub.g.dart';
|
||||
|
||||
@freezed
|
||||
sealed class SnActivityPubInstance with _$SnActivityPubInstance {
|
||||
const factory SnActivityPubInstance({
|
||||
required String id,
|
||||
required String domain,
|
||||
String? name,
|
||||
String? description,
|
||||
String? software,
|
||||
String? version,
|
||||
String? iconUrl,
|
||||
String? thumbnailUrl,
|
||||
String? contactEmail,
|
||||
String? contactAccountUsername,
|
||||
int? activeUsers,
|
||||
@Default(false) bool isBlocked,
|
||||
@Default(false) bool isSilenced,
|
||||
String? blockReason,
|
||||
Map<String, dynamic>? metadata,
|
||||
DateTime? lastFetchedAt,
|
||||
DateTime? lastActivityAt,
|
||||
DateTime? metadataFetchedAt,
|
||||
}) = _SnActivityPubInstance;
|
||||
|
||||
factory SnActivityPubInstance.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnActivityPubInstanceFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnActivityPubUser with _$SnActivityPubUser {
|
||||
const factory SnActivityPubUser({
|
||||
required String actorUri,
|
||||
required String username,
|
||||
required String displayName,
|
||||
required String bio,
|
||||
required String avatarUrl,
|
||||
required DateTime followedAt,
|
||||
required bool isLocal,
|
||||
required String instanceDomain,
|
||||
}) = _SnActivityPubUser;
|
||||
|
||||
factory SnActivityPubUser.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnActivityPubUserFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnActivityPubActor with _$SnActivityPubActor {
|
||||
const factory SnActivityPubActor({
|
||||
required String id,
|
||||
required String uri,
|
||||
@Default('') String type,
|
||||
String? displayName,
|
||||
String? username,
|
||||
String? summary,
|
||||
String? inboxUri,
|
||||
String? outboxUri,
|
||||
String? followersUri,
|
||||
String? followingUri,
|
||||
String? featuredUri,
|
||||
String? avatarUrl,
|
||||
String? headerUrl,
|
||||
String? publicKeyId,
|
||||
String? publicKey,
|
||||
@Default(false) bool isBot,
|
||||
@Default(false) bool isLocked,
|
||||
@Default(true) bool discoverable,
|
||||
@Default(false) bool manuallyApprovesFollowers,
|
||||
Map<String, dynamic>? endpoints,
|
||||
Map<String, dynamic>? publicKeyData,
|
||||
Map<String, dynamic>? metadata,
|
||||
DateTime? lastFetchedAt,
|
||||
DateTime? lastActivityAt,
|
||||
required SnActivityPubInstance instance,
|
||||
required String instanceId,
|
||||
bool? isFollowing,
|
||||
}) = _SnActivityPubActor;
|
||||
|
||||
factory SnActivityPubActor.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnActivityPubActorFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnActivityPubFollowResponse with _$SnActivityPubFollowResponse {
|
||||
const factory SnActivityPubFollowResponse({
|
||||
required bool success,
|
||||
required String message,
|
||||
}) = _SnActivityPubFollowResponse;
|
||||
|
||||
factory SnActivityPubFollowResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnActivityPubFollowResponseFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class SnActorStatusResponse with _$SnActorStatusResponse {
|
||||
const factory SnActorStatusResponse({
|
||||
required bool enabled,
|
||||
@Default(0) int followerCount,
|
||||
SnActivityPubActor? actor,
|
||||
String? actorUri,
|
||||
}) = _SnActorStatusResponse;
|
||||
|
||||
factory SnActorStatusResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnActorStatusResponseFromJson(json);
|
||||
}
|
||||
1535
lib/models/activitypub.freezed.dart
Normal file
1535
lib/models/activitypub.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
186
lib/models/activitypub.g.dart
Normal file
186
lib/models/activitypub.g.dart
Normal file
@@ -0,0 +1,186 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'activitypub.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_SnActivityPubInstance _$SnActivityPubInstanceFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnActivityPubInstance(
|
||||
id: json['id'] as String,
|
||||
domain: json['domain'] as String,
|
||||
name: json['name'] as String?,
|
||||
description: json['description'] as String?,
|
||||
software: json['software'] as String?,
|
||||
version: json['version'] as String?,
|
||||
iconUrl: json['icon_url'] as String?,
|
||||
thumbnailUrl: json['thumbnail_url'] as String?,
|
||||
contactEmail: json['contact_email'] as String?,
|
||||
contactAccountUsername: json['contact_account_username'] as String?,
|
||||
activeUsers: (json['active_users'] as num?)?.toInt(),
|
||||
isBlocked: json['is_blocked'] as bool? ?? false,
|
||||
isSilenced: json['is_silenced'] as bool? ?? false,
|
||||
blockReason: json['block_reason'] as String?,
|
||||
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||
lastFetchedAt: json['last_fetched_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_fetched_at'] as String),
|
||||
lastActivityAt: json['last_activity_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_activity_at'] as String),
|
||||
metadataFetchedAt: json['metadata_fetched_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['metadata_fetched_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnActivityPubInstanceToJson(
|
||||
_SnActivityPubInstance instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'domain': instance.domain,
|
||||
'name': instance.name,
|
||||
'description': instance.description,
|
||||
'software': instance.software,
|
||||
'version': instance.version,
|
||||
'icon_url': instance.iconUrl,
|
||||
'thumbnail_url': instance.thumbnailUrl,
|
||||
'contact_email': instance.contactEmail,
|
||||
'contact_account_username': instance.contactAccountUsername,
|
||||
'active_users': instance.activeUsers,
|
||||
'is_blocked': instance.isBlocked,
|
||||
'is_silenced': instance.isSilenced,
|
||||
'block_reason': instance.blockReason,
|
||||
'metadata': instance.metadata,
|
||||
'last_fetched_at': instance.lastFetchedAt?.toIso8601String(),
|
||||
'last_activity_at': instance.lastActivityAt?.toIso8601String(),
|
||||
'metadata_fetched_at': instance.metadataFetchedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
_SnActivityPubUser _$SnActivityPubUserFromJson(Map<String, dynamic> json) =>
|
||||
_SnActivityPubUser(
|
||||
actorUri: json['actor_uri'] as String,
|
||||
username: json['username'] as String,
|
||||
displayName: json['display_name'] as String,
|
||||
bio: json['bio'] as String,
|
||||
avatarUrl: json['avatar_url'] as String,
|
||||
followedAt: DateTime.parse(json['followed_at'] as String),
|
||||
isLocal: json['is_local'] as bool,
|
||||
instanceDomain: json['instance_domain'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnActivityPubUserToJson(_SnActivityPubUser instance) =>
|
||||
<String, dynamic>{
|
||||
'actor_uri': instance.actorUri,
|
||||
'username': instance.username,
|
||||
'display_name': instance.displayName,
|
||||
'bio': instance.bio,
|
||||
'avatar_url': instance.avatarUrl,
|
||||
'followed_at': instance.followedAt.toIso8601String(),
|
||||
'is_local': instance.isLocal,
|
||||
'instance_domain': instance.instanceDomain,
|
||||
};
|
||||
|
||||
_SnActivityPubActor _$SnActivityPubActorFromJson(Map<String, dynamic> json) =>
|
||||
_SnActivityPubActor(
|
||||
id: json['id'] as String,
|
||||
uri: json['uri'] as String,
|
||||
type: json['type'] as String? ?? '',
|
||||
displayName: json['display_name'] as String?,
|
||||
username: json['username'] as String?,
|
||||
summary: json['summary'] as String?,
|
||||
inboxUri: json['inbox_uri'] as String?,
|
||||
outboxUri: json['outbox_uri'] as String?,
|
||||
followersUri: json['followers_uri'] as String?,
|
||||
followingUri: json['following_uri'] as String?,
|
||||
featuredUri: json['featured_uri'] as String?,
|
||||
avatarUrl: json['avatar_url'] as String?,
|
||||
headerUrl: json['header_url'] as String?,
|
||||
publicKeyId: json['public_key_id'] as String?,
|
||||
publicKey: json['public_key'] as String?,
|
||||
isBot: json['is_bot'] as bool? ?? false,
|
||||
isLocked: json['is_locked'] as bool? ?? false,
|
||||
discoverable: json['discoverable'] as bool? ?? true,
|
||||
manuallyApprovesFollowers:
|
||||
json['manually_approves_followers'] as bool? ?? false,
|
||||
endpoints: json['endpoints'] as Map<String, dynamic>?,
|
||||
publicKeyData: json['public_key_data'] as Map<String, dynamic>?,
|
||||
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||
lastFetchedAt: json['last_fetched_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_fetched_at'] as String),
|
||||
lastActivityAt: json['last_activity_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_activity_at'] as String),
|
||||
instance: SnActivityPubInstance.fromJson(
|
||||
json['instance'] as Map<String, dynamic>,
|
||||
),
|
||||
instanceId: json['instance_id'] as String,
|
||||
isFollowing: json['is_following'] as bool?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnActivityPubActorToJson(_SnActivityPubActor instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'uri': instance.uri,
|
||||
'type': instance.type,
|
||||
'display_name': instance.displayName,
|
||||
'username': instance.username,
|
||||
'summary': instance.summary,
|
||||
'inbox_uri': instance.inboxUri,
|
||||
'outbox_uri': instance.outboxUri,
|
||||
'followers_uri': instance.followersUri,
|
||||
'following_uri': instance.followingUri,
|
||||
'featured_uri': instance.featuredUri,
|
||||
'avatar_url': instance.avatarUrl,
|
||||
'header_url': instance.headerUrl,
|
||||
'public_key_id': instance.publicKeyId,
|
||||
'public_key': instance.publicKey,
|
||||
'is_bot': instance.isBot,
|
||||
'is_locked': instance.isLocked,
|
||||
'discoverable': instance.discoverable,
|
||||
'manually_approves_followers': instance.manuallyApprovesFollowers,
|
||||
'endpoints': instance.endpoints,
|
||||
'public_key_data': instance.publicKeyData,
|
||||
'metadata': instance.metadata,
|
||||
'last_fetched_at': instance.lastFetchedAt?.toIso8601String(),
|
||||
'last_activity_at': instance.lastActivityAt?.toIso8601String(),
|
||||
'instance': instance.instance.toJson(),
|
||||
'instance_id': instance.instanceId,
|
||||
'is_following': instance.isFollowing,
|
||||
};
|
||||
|
||||
_SnActivityPubFollowResponse _$SnActivityPubFollowResponseFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnActivityPubFollowResponse(
|
||||
success: json['success'] as bool,
|
||||
message: json['message'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnActivityPubFollowResponseToJson(
|
||||
_SnActivityPubFollowResponse instance,
|
||||
) => <String, dynamic>{
|
||||
'success': instance.success,
|
||||
'message': instance.message,
|
||||
};
|
||||
|
||||
_SnActorStatusResponse _$SnActorStatusResponseFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnActorStatusResponse(
|
||||
enabled: json['enabled'] as bool,
|
||||
followerCount: (json['follower_count'] as num?)?.toInt() ?? 0,
|
||||
actor: json['actor'] == null
|
||||
? null
|
||||
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
|
||||
actorUri: json['actor_uri'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnActorStatusResponseToJson(
|
||||
_SnActorStatusResponse instance,
|
||||
) => <String, dynamic>{
|
||||
'enabled': instance.enabled,
|
||||
'follower_count': instance.followerCount,
|
||||
'actor': instance.actor?.toJson(),
|
||||
'actor_uri': instance.actorUri,
|
||||
};
|
||||
@@ -55,6 +55,7 @@ sealed class SnCloudFile with _$SnCloudFile {
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
String? url,
|
||||
}) = _SnCloudFile;
|
||||
|
||||
factory SnCloudFile.fromJson(Map<String, dynamic> json) =>
|
||||
|
||||
@@ -281,7 +281,7 @@ as String?,
|
||||
/// @nodoc
|
||||
mixin _$SnCloudFile {
|
||||
|
||||
String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
||||
String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String? get url;
|
||||
/// Create a copy of SnCloudFile
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -294,16 +294,16 @@ $SnCloudFileCopyWith<SnCloudFile> get copyWith => _$SnCloudFileCopyWithImpl<SnCl
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt);
|
||||
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
|
||||
}
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ abstract mixin class $SnCloudFileCopyWith<$Res> {
|
||||
factory $SnCloudFileCopyWith(SnCloudFile value, $Res Function(SnCloudFile) _then) = _$SnCloudFileCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
|
||||
});
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ class _$SnCloudFileCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnCloudFile
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
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
|
||||
@@ -348,7 +348,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
|
||||
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as 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?,
|
||||
as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of SnCloudFile
|
||||
@@ -442,10 +443,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnCloudFile() when $default != null:
|
||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -463,10 +464,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnCloudFile():
|
||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -480,10 +481,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnCloudFile() when $default != null:
|
||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -495,7 +496,7 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnCloudFile implements SnCloudFile {
|
||||
const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks;
|
||||
const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt, this.url}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks;
|
||||
factory _SnCloudFile.fromJson(Map<String, dynamic> json) => _$SnCloudFileFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@@ -535,6 +536,7 @@ class _SnCloudFile implements SnCloudFile {
|
||||
@override final DateTime createdAt;
|
||||
@override final DateTime updatedAt;
|
||||
@override final DateTime? deletedAt;
|
||||
@override final String? url;
|
||||
|
||||
/// Create a copy of SnCloudFile
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -549,16 +551,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt);
|
||||
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
|
||||
}
|
||||
|
||||
|
||||
@@ -569,7 +571,7 @@ abstract mixin class _$SnCloudFileCopyWith<$Res> implements $SnCloudFileCopyWith
|
||||
factory _$SnCloudFileCopyWith(_SnCloudFile value, $Res Function(_SnCloudFile) _then) = __$SnCloudFileCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
|
||||
});
|
||||
|
||||
|
||||
@@ -586,7 +588,7 @@ class __$SnCloudFileCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnCloudFile
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
|
||||
return _then(_SnCloudFile(
|
||||
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
|
||||
@@ -603,7 +605,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
|
||||
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as 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?,
|
||||
as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ _SnCloudFile _$SnCloudFileFromJson(Map<String, dynamic> json) => _SnCloudFile(
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
url: json['url'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
|
||||
@@ -74,6 +75,7 @@ Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'url': instance.url,
|
||||
};
|
||||
|
||||
_SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) =>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/models/activitypub.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/models/post_category.dart';
|
||||
import 'package:island/models/post_tag.dart';
|
||||
@@ -39,8 +40,14 @@ sealed class SnPost with _$SnPost {
|
||||
SnPost? forwardedPost,
|
||||
String? realmId,
|
||||
SnRealm? realm,
|
||||
String? publisherId,
|
||||
SnPublisher? publisher,
|
||||
String? actorid,
|
||||
SnActivityPubActor? actor,
|
||||
String? fediverseUri,
|
||||
int? fediverseType,
|
||||
@Default(0) int contentType,
|
||||
@Default([]) List<SnCloudFile> attachments,
|
||||
required SnPublisher publisher,
|
||||
@Default({}) Map<String, int> reactionsCount,
|
||||
@Default({}) Map<String, bool> reactionsMade,
|
||||
@Default([]) List<dynamic> reactions,
|
||||
@@ -155,10 +162,12 @@ sealed class SnPostReaction with _$SnPostReaction {
|
||||
required String symbol,
|
||||
required int attitude,
|
||||
required String postId,
|
||||
required String accountId,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
@Default(null) SnAccount? account,
|
||||
String? actorId,
|
||||
SnActivityPubActor? actor,
|
||||
String? accountId,
|
||||
SnAccount? account,
|
||||
DateTime? deletedAt,
|
||||
}) = _SnPostReaction;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$SnPost {
|
||||
|
||||
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; SnPostEmbedView? get embedView; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int get awardedScore; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List<SnCloudFile> get attachments; SnPublisher get publisher; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; List<SnPostFeaturedRecord> get featuredRecords; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get repliedGone; bool get forwardedGone; bool get isTruncated;
|
||||
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; SnPostEmbedView? get embedView; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int get awardedScore; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; String? get publisherId; SnPublisher? get publisher; String? get actorid; SnActivityPubActor? get actor; String? get fediverseUri; int? get fediverseType; int get contentType; List<SnCloudFile> get attachments; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; List<SnPostFeaturedRecord> get featuredRecords; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get repliedGone; bool get forwardedGone; bool get isTruncated;
|
||||
/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -28,16 +28,16 @@ $SnPostCopyWith<SnPost> get copyWith => _$SnPostCopyWithImpl<SnPost>(this as SnP
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&const DeepCollectionEquality().equals(other.featuredRecords, featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.actorid, actorid) || other.actorid == actorid)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.fediverseUri, fediverseUri) || other.fediverseUri == fediverseUri)&&(identical(other.fediverseType, fediverseType) || other.fediverseType == fediverseType)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&const DeepCollectionEquality().equals(other.featuredRecords, featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),const DeepCollectionEquality().hash(featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,publisherId,publisher,actorid,actor,fediverseUri,fediverseType,contentType,const DeepCollectionEquality().hash(attachments),const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),const DeepCollectionEquality().hash(featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, publisherId: $publisherId, publisher: $publisher, actorid: $actorid, actor: $actor, fediverseUri: $fediverseUri, fediverseType: $fediverseType, contentType: $contentType, attachments: $attachments, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,11 @@ abstract mixin class $SnPostCopyWith<$Res> {
|
||||
factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
||||
});
|
||||
|
||||
|
||||
$SnPostEmbedViewCopyWith<$Res>? get embedView;$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res> get publisher;
|
||||
$SnPostEmbedViewCopyWith<$Res>? get embedView;$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res>? get publisher;$SnActivityPubActorCopyWith<$Res>? get actor;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? publisherId = freezed,Object? publisher = freezed,Object? actorid = freezed,Object? actor = freezed,Object? fediverseUri = freezed,Object? fediverseType = freezed,Object? contentType = null,Object? attachments = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
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
|
||||
@@ -94,9 +94,15 @@ as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId :
|
||||
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
||||
as SnRealm?,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||
as SnPublisher,reactionsCount: null == reactionsCount ? _self.reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||
as SnRealm?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||
as SnPublisher?,actorid: freezed == actorid ? _self.actorid : actorid // ignore: cast_nullable_to_non_nullable
|
||||
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||
as SnActivityPubActor?,fediverseUri: freezed == fediverseUri ? _self.fediverseUri : fediverseUri // ignore: cast_nullable_to_non_nullable
|
||||
as String?,fediverseType: freezed == fediverseType ? _self.fediverseType : fediverseType // ignore: cast_nullable_to_non_nullable
|
||||
as int?,contentType: null == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||
as int,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnCloudFile>,reactionsCount: null == reactionsCount ? _self.reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, int>,reactionsMade: null == reactionsMade ? _self.reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, bool>,reactions: null == reactions ? _self.reactions : reactions // ignore: cast_nullable_to_non_nullable
|
||||
as List<dynamic>,tags: null == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
|
||||
@@ -176,11 +182,26 @@ $SnRealmCopyWith<$Res>? get realm {
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnPublisherCopyWith<$Res> get publisher {
|
||||
|
||||
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
|
||||
$SnPublisherCopyWith<$Res>? get publisher {
|
||||
if (_self.publisher == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) {
|
||||
return _then(_self.copyWith(publisher: value));
|
||||
});
|
||||
}/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||
if (_self.actor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||
return _then(_self.copyWith(actor: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,10 +281,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPost() when $default != null:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -281,10 +302,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPost():
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);}
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -298,10 +319,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPost() when $default != null:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -313,7 +334,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnPost implements SnPost {
|
||||
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.embedView, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.awardedScore = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final List<SnCloudFile> attachments = const [], required this.publisher, final Map<String, int> reactionsCount = const {}, final Map<String, bool> reactionsMade = const {}, final List<dynamic> reactions = const [], final List<SnPostTag> tags = const [], final List<SnPostCategory> categories = const [], final List<dynamic> collections = const [], final List<SnPostFeaturedRecord> featuredRecords = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.repliedGone = false, this.forwardedGone = false, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections,_featuredRecords = featuredRecords;
|
||||
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.embedView, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.awardedScore = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, this.publisherId, this.publisher, this.actorid, this.actor, this.fediverseUri, this.fediverseType, this.contentType = 0, final List<SnCloudFile> attachments = const [], final Map<String, int> reactionsCount = const {}, final Map<String, bool> reactionsMade = const {}, final List<dynamic> reactions = const [], final List<SnPostTag> tags = const [], final List<SnPostCategory> categories = const [], final List<dynamic> collections = const [], final List<SnPostFeaturedRecord> featuredRecords = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.repliedGone = false, this.forwardedGone = false, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections,_featuredRecords = featuredRecords;
|
||||
factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@@ -351,6 +372,13 @@ class _SnPost implements SnPost {
|
||||
@override final SnPost? forwardedPost;
|
||||
@override final String? realmId;
|
||||
@override final SnRealm? realm;
|
||||
@override final String? publisherId;
|
||||
@override final SnPublisher? publisher;
|
||||
@override final String? actorid;
|
||||
@override final SnActivityPubActor? actor;
|
||||
@override final String? fediverseUri;
|
||||
@override final int? fediverseType;
|
||||
@override@JsonKey() final int contentType;
|
||||
final List<SnCloudFile> _attachments;
|
||||
@override@JsonKey() List<SnCloudFile> get attachments {
|
||||
if (_attachments is EqualUnmodifiableListView) return _attachments;
|
||||
@@ -358,7 +386,6 @@ class _SnPost implements SnPost {
|
||||
return EqualUnmodifiableListView(_attachments);
|
||||
}
|
||||
|
||||
@override final SnPublisher publisher;
|
||||
final Map<String, int> _reactionsCount;
|
||||
@override@JsonKey() Map<String, int> get reactionsCount {
|
||||
if (_reactionsCount is EqualUnmodifiableMapView) return _reactionsCount;
|
||||
@@ -428,16 +455,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&const DeepCollectionEquality().equals(other._featuredRecords, _featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.actorid, actorid) || other.actorid == actorid)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.fediverseUri, fediverseUri) || other.fediverseUri == fediverseUri)&&(identical(other.fediverseType, fediverseType) || other.fediverseType == fediverseType)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&const DeepCollectionEquality().equals(other._featuredRecords, _featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),const DeepCollectionEquality().hash(_featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,publisherId,publisher,actorid,actor,fediverseUri,fediverseType,contentType,const DeepCollectionEquality().hash(_attachments),const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),const DeepCollectionEquality().hash(_featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, publisherId: $publisherId, publisher: $publisher, actorid: $actorid, actor: $actor, fediverseUri: $fediverseUri, fediverseType: $fediverseType, contentType: $contentType, attachments: $attachments, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
|
||||
}
|
||||
|
||||
|
||||
@@ -448,11 +475,11 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> {
|
||||
factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
|
||||
});
|
||||
|
||||
|
||||
@override $SnPostEmbedViewCopyWith<$Res>? get embedView;@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnRealmCopyWith<$Res>? get realm;@override $SnPublisherCopyWith<$Res> get publisher;
|
||||
@override $SnPostEmbedViewCopyWith<$Res>? get embedView;@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnRealmCopyWith<$Res>? get realm;@override $SnPublisherCopyWith<$Res>? get publisher;@override $SnActivityPubActorCopyWith<$Res>? get actor;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -465,7 +492,7 @@ class __$SnPostCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? publisherId = freezed,Object? publisher = freezed,Object? actorid = freezed,Object? actor = freezed,Object? fediverseUri = freezed,Object? fediverseType = freezed,Object? contentType = null,Object? attachments = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
|
||||
return _then(_SnPost(
|
||||
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
|
||||
@@ -494,9 +521,15 @@ as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId :
|
||||
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
||||
as SnRealm?,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||
as SnPublisher,reactionsCount: null == reactionsCount ? _self._reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||
as SnRealm?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||
as SnPublisher?,actorid: freezed == actorid ? _self.actorid : actorid // ignore: cast_nullable_to_non_nullable
|
||||
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||
as SnActivityPubActor?,fediverseUri: freezed == fediverseUri ? _self.fediverseUri : fediverseUri // ignore: cast_nullable_to_non_nullable
|
||||
as String?,fediverseType: freezed == fediverseType ? _self.fediverseType : fediverseType // ignore: cast_nullable_to_non_nullable
|
||||
as int?,contentType: null == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||
as int,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnCloudFile>,reactionsCount: null == reactionsCount ? _self._reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, int>,reactionsMade: null == reactionsMade ? _self._reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, bool>,reactions: null == reactions ? _self._reactions : reactions // ignore: cast_nullable_to_non_nullable
|
||||
as List<dynamic>,tags: null == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
|
||||
@@ -577,11 +610,26 @@ $SnRealmCopyWith<$Res>? get realm {
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnPublisherCopyWith<$Res> get publisher {
|
||||
|
||||
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
|
||||
$SnPublisherCopyWith<$Res>? get publisher {
|
||||
if (_self.publisher == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) {
|
||||
return _then(_self.copyWith(publisher: value));
|
||||
});
|
||||
}/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||
if (_self.actor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||
return _then(_self.copyWith(actor: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1937,7 +1985,7 @@ as DateTime?,
|
||||
/// @nodoc
|
||||
mixin _$SnPostReaction {
|
||||
|
||||
String get id; String get symbol; int get attitude; String get postId; String get accountId; DateTime get createdAt; DateTime get updatedAt; SnAccount? get account; DateTime? get deletedAt;
|
||||
String get id; String get symbol; int get attitude; String get postId; DateTime get createdAt; DateTime get updatedAt; String? get actorId; SnActivityPubActor? get actor; String? get accountId; SnAccount? get account; DateTime? get deletedAt;
|
||||
/// Create a copy of SnPostReaction
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -1950,16 +1998,16 @@ $SnPostReactionCopyWith<SnPostReaction> get copyWith => _$SnPostReactionCopyWith
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.actorId, actorId) || other.actorId == actorId)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,accountId,createdAt,updatedAt,account,deletedAt);
|
||||
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,createdAt,updatedAt,actorId,actor,accountId,account,deletedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, account: $account, deletedAt: $deletedAt)';
|
||||
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, createdAt: $createdAt, updatedAt: $updatedAt, actorId: $actorId, actor: $actor, accountId: $accountId, account: $account, deletedAt: $deletedAt)';
|
||||
}
|
||||
|
||||
|
||||
@@ -1970,11 +2018,11 @@ abstract mixin class $SnPostReactionCopyWith<$Res> {
|
||||
factory $SnPostReactionCopyWith(SnPostReaction value, $Res Function(SnPostReaction) _then) = _$SnPostReactionCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt
|
||||
String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt
|
||||
});
|
||||
|
||||
|
||||
$SnAccountCopyWith<$Res>? get account;
|
||||
$SnActivityPubActorCopyWith<$Res>? get actor;$SnAccountCopyWith<$Res>? get account;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -1987,16 +2035,18 @@ class _$SnPostReactionCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPostReaction
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? account = freezed,Object? deletedAt = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? createdAt = null,Object? updatedAt = null,Object? actorId = freezed,Object? actor = freezed,Object? accountId = freezed,Object? account = freezed,Object? deletedAt = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
|
||||
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
|
||||
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
|
||||
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,actorId: freezed == actorId ? _self.actorId : actorId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||
as SnActivityPubActor?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||
as SnAccount?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
));
|
||||
@@ -2005,6 +2055,18 @@ as DateTime?,
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||
if (_self.actor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||
return _then(_self.copyWith(actor: value));
|
||||
});
|
||||
}/// Create a copy of SnPostReaction
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnAccountCopyWith<$Res>? get account {
|
||||
if (_self.account == null) {
|
||||
return null;
|
||||
@@ -2092,10 +2154,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostReaction() when $default != null:
|
||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);case _:
|
||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -2113,10 +2175,10 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostReaction():
|
||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);}
|
||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -2130,10 +2192,10 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPostReaction() when $default != null:
|
||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);case _:
|
||||
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -2145,17 +2207,19 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnPostReaction implements SnPostReaction {
|
||||
const _SnPostReaction({required this.id, required this.symbol, required this.attitude, required this.postId, required this.accountId, required this.createdAt, required this.updatedAt, this.account = null, this.deletedAt});
|
||||
const _SnPostReaction({required this.id, required this.symbol, required this.attitude, required this.postId, required this.createdAt, required this.updatedAt, this.actorId, this.actor, this.accountId, this.account, this.deletedAt});
|
||||
factory _SnPostReaction.fromJson(Map<String, dynamic> json) => _$SnPostReactionFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@override final String symbol;
|
||||
@override final int attitude;
|
||||
@override final String postId;
|
||||
@override final String accountId;
|
||||
@override final DateTime createdAt;
|
||||
@override final DateTime updatedAt;
|
||||
@override@JsonKey() final SnAccount? account;
|
||||
@override final String? actorId;
|
||||
@override final SnActivityPubActor? actor;
|
||||
@override final String? accountId;
|
||||
@override final SnAccount? account;
|
||||
@override final DateTime? deletedAt;
|
||||
|
||||
/// Create a copy of SnPostReaction
|
||||
@@ -2171,16 +2235,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.actorId, actorId) || other.actorId == actorId)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,accountId,createdAt,updatedAt,account,deletedAt);
|
||||
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,createdAt,updatedAt,actorId,actor,accountId,account,deletedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, account: $account, deletedAt: $deletedAt)';
|
||||
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, createdAt: $createdAt, updatedAt: $updatedAt, actorId: $actorId, actor: $actor, accountId: $accountId, account: $account, deletedAt: $deletedAt)';
|
||||
}
|
||||
|
||||
|
||||
@@ -2191,11 +2255,11 @@ abstract mixin class _$SnPostReactionCopyWith<$Res> implements $SnPostReactionCo
|
||||
factory _$SnPostReactionCopyWith(_SnPostReaction value, $Res Function(_SnPostReaction) _then) = __$SnPostReactionCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt
|
||||
String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt
|
||||
});
|
||||
|
||||
|
||||
@override $SnAccountCopyWith<$Res>? get account;
|
||||
@override $SnActivityPubActorCopyWith<$Res>? get actor;@override $SnAccountCopyWith<$Res>? get account;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -2208,16 +2272,18 @@ class __$SnPostReactionCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPostReaction
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? account = freezed,Object? deletedAt = freezed,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? createdAt = null,Object? updatedAt = null,Object? actorId = freezed,Object? actor = freezed,Object? accountId = freezed,Object? account = freezed,Object? deletedAt = freezed,}) {
|
||||
return _then(_SnPostReaction(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
|
||||
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
|
||||
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
|
||||
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,actorId: freezed == actorId ? _self.actorId : actorId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
|
||||
as SnActivityPubActor?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||
as SnAccount?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
));
|
||||
@@ -2227,6 +2293,18 @@ as DateTime?,
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnActivityPubActorCopyWith<$Res>? get actor {
|
||||
if (_self.actor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
|
||||
return _then(_self.copyWith(actor: value));
|
||||
});
|
||||
}/// Create a copy of SnPostReaction
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnAccountCopyWith<$Res>? get account {
|
||||
if (_self.account == null) {
|
||||
return null;
|
||||
|
||||
@@ -48,12 +48,22 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
|
||||
realm: json['realm'] == null
|
||||
? null
|
||||
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
|
||||
publisherId: json['publisher_id'] as String?,
|
||||
publisher: json['publisher'] == null
|
||||
? null
|
||||
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
|
||||
actorid: json['actorid'] as String?,
|
||||
actor: json['actor'] == null
|
||||
? null
|
||||
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
|
||||
fediverseUri: json['fediverse_uri'] as String?,
|
||||
fediverseType: (json['fediverse_type'] as num?)?.toInt(),
|
||||
contentType: (json['content_type'] as num?)?.toInt() ?? 0,
|
||||
attachments:
|
||||
(json['attachments'] as List<dynamic>?)
|
||||
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
const [],
|
||||
publisher: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
|
||||
reactionsCount:
|
||||
(json['reactions_count'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, (e as num).toInt()),
|
||||
@@ -123,8 +133,14 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
|
||||
'forwarded_post': instance.forwardedPost?.toJson(),
|
||||
'realm_id': instance.realmId,
|
||||
'realm': instance.realm?.toJson(),
|
||||
'publisher_id': instance.publisherId,
|
||||
'publisher': instance.publisher?.toJson(),
|
||||
'actorid': instance.actorid,
|
||||
'actor': instance.actor?.toJson(),
|
||||
'fediverse_uri': instance.fediverseUri,
|
||||
'fediverse_type': instance.fediverseType,
|
||||
'content_type': instance.contentType,
|
||||
'attachments': instance.attachments.map((e) => e.toJson()).toList(),
|
||||
'publisher': instance.publisher.toJson(),
|
||||
'reactions_count': instance.reactionsCount,
|
||||
'reactions_made': instance.reactionsMade,
|
||||
'reactions': instance.reactions,
|
||||
@@ -232,9 +248,13 @@ _SnPostReaction _$SnPostReactionFromJson(Map<String, dynamic> json) =>
|
||||
symbol: json['symbol'] as String,
|
||||
attitude: (json['attitude'] as num).toInt(),
|
||||
postId: json['post_id'] as String,
|
||||
accountId: json['account_id'] as String,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
actorId: json['actor_id'] as String?,
|
||||
actor: json['actor'] == null
|
||||
? null
|
||||
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
|
||||
accountId: json['account_id'] as String?,
|
||||
account: json['account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||
@@ -249,9 +269,11 @@ Map<String, dynamic> _$SnPostReactionToJson(_SnPostReaction instance) =>
|
||||
'symbol': instance.symbol,
|
||||
'attitude': instance.attitude,
|
||||
'post_id': instance.postId,
|
||||
'account_id': instance.accountId,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'actor_id': instance.actorId,
|
||||
'actor': instance.actor?.toJson(),
|
||||
'account_id': instance.accountId,
|
||||
'account': instance.account?.toJson(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
@@ -32,10 +32,10 @@ final List<RouteItem> kAvailableRoutes = [
|
||||
icon: Symbols.explore,
|
||||
),
|
||||
RouteItem(
|
||||
name: 'searchPosts'.tr(),
|
||||
path: '/posts/search',
|
||||
description: 'searchPostsDescription'.tr(),
|
||||
searchableAliases: ['search', 'posts'],
|
||||
name: 'universalSearch'.tr(),
|
||||
path: '/search',
|
||||
description: 'universalSearchDescription'.tr(),
|
||||
searchableAliases: ['search', 'universal', 'fediverse'],
|
||||
icon: Symbols.search,
|
||||
),
|
||||
RouteItem(
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'activity_rpc.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(presenceActivities)
|
||||
const presenceActivitiesProvider = PresenceActivitiesFamily._();
|
||||
final presenceActivitiesProvider = PresenceActivitiesFamily._();
|
||||
|
||||
final class PresenceActivitiesProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class PresenceActivitiesProvider
|
||||
with
|
||||
$FutureModifier<List<SnPresenceActivity>>,
|
||||
$FutureProvider<List<SnPresenceActivity>> {
|
||||
const PresenceActivitiesProvider._({
|
||||
PresenceActivitiesProvider._({
|
||||
required PresenceActivitiesFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -71,7 +71,7 @@ String _$presenceActivitiesHash() =>
|
||||
|
||||
final class PresenceActivitiesFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<SnPresenceActivity>>, String> {
|
||||
const PresenceActivitiesFamily._()
|
||||
PresenceActivitiesFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'presenceActivitiesProvider',
|
||||
|
||||
@@ -10,7 +10,7 @@ final articleDetailProvider = FutureProvider.autoDispose
|
||||
|
||||
try {
|
||||
final response = await dio.get<Map<String, dynamic>>(
|
||||
'/sphere/feeds/articles/$articleId',
|
||||
'/insight/feeds/articles/$articleId',
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 && response.data != null) {
|
||||
|
||||
@@ -16,6 +16,8 @@ import 'package:island/talker.dart';
|
||||
part 'call.g.dart';
|
||||
part 'call.freezed.dart';
|
||||
|
||||
enum ViewMode { grid, stage }
|
||||
|
||||
String formatDuration(Duration duration) {
|
||||
String negativeSign = duration.isNegative ? '-' : '';
|
||||
String twoDigits(int n) => n.toString().padLeft(2, "0");
|
||||
@@ -33,6 +35,7 @@ sealed class CallState with _$CallState {
|
||||
required bool isScreenSharing,
|
||||
required bool isSpeakerphone,
|
||||
@Default(Duration(seconds: 0)) Duration duration,
|
||||
@Default(ViewMode.grid) ViewMode viewMode,
|
||||
String? error,
|
||||
}) = _CallState;
|
||||
}
|
||||
@@ -84,6 +87,7 @@ class CallNotifier extends _$CallNotifier {
|
||||
isCameraEnabled: false,
|
||||
isScreenSharing: false,
|
||||
isSpeakerphone: true,
|
||||
viewMode: ViewMode.grid,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -241,7 +245,7 @@ class CallNotifier extends _$CallNotifier {
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final ongoingCall = await ref.read(ongoingCallProvider(roomId).future);
|
||||
final response = await apiClient.get(
|
||||
'/sphere/chat/realtime/$roomId/join',
|
||||
'/messager/chat/realtime/$roomId/join',
|
||||
);
|
||||
if (response.statusCode == 200 && response.data != null) {
|
||||
final data = response.data;
|
||||
@@ -258,8 +262,8 @@ class CallNotifier extends _$CallNotifier {
|
||||
duration: Duration(
|
||||
milliseconds:
|
||||
(DateTime.now().millisecondsSinceEpoch -
|
||||
(ongoingCall?.createdAt.millisecondsSinceEpoch ??
|
||||
DateTime.now().millisecondsSinceEpoch)),
|
||||
(ongoingCall?.createdAt.millisecondsSinceEpoch ??
|
||||
DateTime.now().millisecondsSinceEpoch)),
|
||||
),
|
||||
);
|
||||
});
|
||||
@@ -418,6 +422,14 @@ class CallNotifier extends _$CallNotifier {
|
||||
return participantsVolumes[live.remoteParticipant.sid] ?? 1;
|
||||
}
|
||||
|
||||
void toggleViewMode() {
|
||||
state = state.copyWith(
|
||||
viewMode: state.viewMode == ViewMode.grid
|
||||
? ViewMode.stage
|
||||
: ViewMode.grid,
|
||||
);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
state = state.copyWith(
|
||||
error: null,
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$CallState implements DiagnosticableTreeMixin {
|
||||
|
||||
bool get isConnected; bool get isMicrophoneEnabled; bool get isCameraEnabled; bool get isScreenSharing; bool get isSpeakerphone; Duration get duration; String? get error;
|
||||
bool get isConnected; bool get isMicrophoneEnabled; bool get isCameraEnabled; bool get isScreenSharing; bool get isSpeakerphone; Duration get duration; ViewMode get viewMode; String? get error;
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -26,21 +26,21 @@ $CallStateCopyWith<CallState> get copyWith => _$CallStateCopyWithImpl<CallState>
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'CallState'))
|
||||
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('error', error));
|
||||
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('viewMode', viewMode))..add(DiagnosticsProperty('error', error));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.viewMode, viewMode) || other.viewMode == viewMode)&&(identical(other.error, error) || other.error == error));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,error);
|
||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,viewMode,error);
|
||||
|
||||
@override
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, error: $error)';
|
||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, viewMode: $viewMode, error: $error)';
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ abstract mixin class $CallStateCopyWith<$Res> {
|
||||
factory $CallStateCopyWith(CallState value, $Res Function(CallState) _then) = _$CallStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error
|
||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error
|
||||
});
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class _$CallStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? error = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? viewMode = null,Object? error = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||
@@ -76,7 +76,8 @@ as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCam
|
||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
||||
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as Duration,viewMode: null == viewMode ? _self.viewMode : viewMode // ignore: cast_nullable_to_non_nullable
|
||||
as ViewMode,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
@@ -159,10 +160,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallState() when $default != null:
|
||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);case _:
|
||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.viewMode,_that.error);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -180,10 +181,10 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallState():
|
||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);}
|
||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.viewMode,_that.error);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -197,10 +198,10 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallState() when $default != null:
|
||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.error);case _:
|
||||
return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnabled,_that.isScreenSharing,_that.isSpeakerphone,_that.duration,_that.viewMode,_that.error);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -212,7 +213,7 @@ return $default(_that.isConnected,_that.isMicrophoneEnabled,_that.isCameraEnable
|
||||
|
||||
|
||||
class _CallState with DiagnosticableTreeMixin implements CallState {
|
||||
const _CallState({required this.isConnected, required this.isMicrophoneEnabled, required this.isCameraEnabled, required this.isScreenSharing, required this.isSpeakerphone, this.duration = const Duration(seconds: 0), this.error});
|
||||
const _CallState({required this.isConnected, required this.isMicrophoneEnabled, required this.isCameraEnabled, required this.isScreenSharing, required this.isSpeakerphone, this.duration = const Duration(seconds: 0), this.viewMode = ViewMode.grid, this.error});
|
||||
|
||||
|
||||
@override final bool isConnected;
|
||||
@@ -221,6 +222,7 @@ class _CallState with DiagnosticableTreeMixin implements CallState {
|
||||
@override final bool isScreenSharing;
|
||||
@override final bool isSpeakerphone;
|
||||
@override@JsonKey() final Duration duration;
|
||||
@override@JsonKey() final ViewMode viewMode;
|
||||
@override final String? error;
|
||||
|
||||
/// Create a copy of CallState
|
||||
@@ -234,21 +236,21 @@ _$CallStateCopyWith<_CallState> get copyWith => __$CallStateCopyWithImpl<_CallSt
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'CallState'))
|
||||
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('error', error));
|
||||
..add(DiagnosticsProperty('isConnected', isConnected))..add(DiagnosticsProperty('isMicrophoneEnabled', isMicrophoneEnabled))..add(DiagnosticsProperty('isCameraEnabled', isCameraEnabled))..add(DiagnosticsProperty('isScreenSharing', isScreenSharing))..add(DiagnosticsProperty('isSpeakerphone', isSpeakerphone))..add(DiagnosticsProperty('duration', duration))..add(DiagnosticsProperty('viewMode', viewMode))..add(DiagnosticsProperty('error', error));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.error, error) || other.error == error));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallState&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.isMicrophoneEnabled, isMicrophoneEnabled) || other.isMicrophoneEnabled == isMicrophoneEnabled)&&(identical(other.isCameraEnabled, isCameraEnabled) || other.isCameraEnabled == isCameraEnabled)&&(identical(other.isScreenSharing, isScreenSharing) || other.isScreenSharing == isScreenSharing)&&(identical(other.isSpeakerphone, isSpeakerphone) || other.isSpeakerphone == isSpeakerphone)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.viewMode, viewMode) || other.viewMode == viewMode)&&(identical(other.error, error) || other.error == error));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,error);
|
||||
int get hashCode => Object.hash(runtimeType,isConnected,isMicrophoneEnabled,isCameraEnabled,isScreenSharing,isSpeakerphone,duration,viewMode,error);
|
||||
|
||||
@override
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, error: $error)';
|
||||
return 'CallState(isConnected: $isConnected, isMicrophoneEnabled: $isMicrophoneEnabled, isCameraEnabled: $isCameraEnabled, isScreenSharing: $isScreenSharing, isSpeakerphone: $isSpeakerphone, duration: $duration, viewMode: $viewMode, error: $error)';
|
||||
}
|
||||
|
||||
|
||||
@@ -259,7 +261,7 @@ abstract mixin class _$CallStateCopyWith<$Res> implements $CallStateCopyWith<$Re
|
||||
factory _$CallStateCopyWith(_CallState value, $Res Function(_CallState) _then) = __$CallStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, String? error
|
||||
bool isConnected, bool isMicrophoneEnabled, bool isCameraEnabled, bool isScreenSharing, bool isSpeakerphone, Duration duration, ViewMode viewMode, String? error
|
||||
});
|
||||
|
||||
|
||||
@@ -276,7 +278,7 @@ class __$CallStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of CallState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? error = freezed,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isConnected = null,Object? isMicrophoneEnabled = null,Object? isCameraEnabled = null,Object? isScreenSharing = null,Object? isSpeakerphone = null,Object? duration = null,Object? viewMode = null,Object? error = freezed,}) {
|
||||
return _then(_CallState(
|
||||
isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isMicrophoneEnabled: null == isMicrophoneEnabled ? _self.isMicrophoneEnabled : isMicrophoneEnabled // ignore: cast_nullable_to_non_nullable
|
||||
@@ -284,7 +286,8 @@ as bool,isCameraEnabled: null == isCameraEnabled ? _self.isCameraEnabled : isCam
|
||||
as bool,isScreenSharing: null == isScreenSharing ? _self.isScreenSharing : isScreenSharing // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isSpeakerphone: null == isSpeakerphone ? _self.isSpeakerphone : isSpeakerphone // ignore: cast_nullable_to_non_nullable
|
||||
as bool,duration: null == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable
|
||||
as Duration,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as Duration,viewMode: null == viewMode ? _self.viewMode : viewMode // ignore: cast_nullable_to_non_nullable
|
||||
as ViewMode,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'call.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(CallNotifier)
|
||||
const callProvider = CallNotifierProvider._();
|
||||
final callProvider = CallNotifierProvider._();
|
||||
|
||||
final class CallNotifierProvider
|
||||
extends $NotifierProvider<CallNotifier, CallState> {
|
||||
const CallNotifierProvider._()
|
||||
CallNotifierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -41,14 +41,13 @@ final class CallNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$callNotifierHash() => r'ef4e3e9c9d411cf9dce1ceb456a3b866b2c87db3';
|
||||
String _$callNotifierHash() => r'caa03913d98c6d98448af44059db5ef72b5d58f6';
|
||||
|
||||
abstract class _$CallNotifier extends $Notifier<CallState> {
|
||||
CallState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<CallState, CallState>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -58,6 +57,6 @@ abstract class _$CallNotifier extends $Notifier<CallState> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class ChatOnlineCountNotifier extends _$ChatOnlineCountNotifier {
|
||||
|
||||
// Fetch initial online count
|
||||
final response = await apiClient.get(
|
||||
'/sphere/chat/$chatroomId/members/online',
|
||||
'/messager/chat/$chatroomId/members/online',
|
||||
);
|
||||
final initialCount = response.data as int;
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'chat_online_count.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ChatOnlineCountNotifier)
|
||||
const chatOnlineCountProvider = ChatOnlineCountNotifierFamily._();
|
||||
final chatOnlineCountProvider = ChatOnlineCountNotifierFamily._();
|
||||
|
||||
final class ChatOnlineCountNotifierProvider
|
||||
extends $AsyncNotifierProvider<ChatOnlineCountNotifier, int> {
|
||||
const ChatOnlineCountNotifierProvider._({
|
||||
ChatOnlineCountNotifierProvider._({
|
||||
required ChatOnlineCountNotifierFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -52,7 +52,7 @@ final class ChatOnlineCountNotifierProvider
|
||||
}
|
||||
|
||||
String _$chatOnlineCountNotifierHash() =>
|
||||
r'19af8fd0e9f62c65e12a68215406776085235fa3';
|
||||
r'b2f9f17bfece1937ec90590b8f11db2bec923156';
|
||||
|
||||
final class ChatOnlineCountNotifierFamily extends $Family
|
||||
with
|
||||
@@ -63,7 +63,7 @@ final class ChatOnlineCountNotifierFamily extends $Family
|
||||
FutureOr<int>,
|
||||
String
|
||||
> {
|
||||
const ChatOnlineCountNotifierFamily._()
|
||||
ChatOnlineCountNotifierFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'chatOnlineCountProvider',
|
||||
@@ -87,7 +87,6 @@ abstract class _$ChatOnlineCountNotifier extends $AsyncNotifier<int> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args);
|
||||
final ref = this.ref as $Ref<AsyncValue<int>, int>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -97,6 +96,6 @@ abstract class _$ChatOnlineCountNotifier extends $AsyncNotifier<int> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
|
||||
Future(() async {
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final resp = await client.get('/sphere/chat');
|
||||
final resp = await client.get('/messager/chat');
|
||||
final remoteRooms = resp.data
|
||||
.map((e) => SnChatRoom.fromJson(e))
|
||||
.cast<SnChatRoom>()
|
||||
@@ -122,7 +122,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
|
||||
|
||||
// Fallback to API
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get('/sphere/chat');
|
||||
final resp = await client.get('/messager/chat');
|
||||
final rooms = resp.data
|
||||
.map((e) => SnChatRoom.fromJson(e))
|
||||
.cast<SnChatRoom>()
|
||||
@@ -306,7 +306,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
|
||||
Future(() async {
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final resp = await client.get('/sphere/chat/$identifier');
|
||||
final resp = await client.get('/messager/chat/$identifier');
|
||||
final remoteRoom = SnChatRoom.fromJson(resp.data);
|
||||
// Update state with fresh data directly without saving to DB
|
||||
// DB will be updated by ChatRoomJoinedNotifier's full sync
|
||||
@@ -321,7 +321,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
|
||||
// Fallback to API
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get('/sphere/chat/$identifier');
|
||||
final resp = await client.get('/messager/chat/$identifier');
|
||||
final room = SnChatRoom.fromJson(resp.data);
|
||||
await db.saveChatRooms([room]);
|
||||
return room;
|
||||
@@ -375,7 +375,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final resp = await client.get(
|
||||
'/sphere/chat/$identifier/members/me',
|
||||
'/messager/chat/$identifier/members/me',
|
||||
);
|
||||
final remoteMember = SnChatMember.fromJson(resp.data);
|
||||
await db.saveMember(remoteMember);
|
||||
@@ -396,7 +396,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
||||
// Fallback to API
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get('/sphere/chat/$identifier/members/me');
|
||||
final resp = await client.get('/messager/chat/$identifier/members/me');
|
||||
final member = SnChatMember.fromJson(resp.data);
|
||||
await db.saveMember(member);
|
||||
return member;
|
||||
@@ -444,7 +444,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
||||
@riverpod
|
||||
Future<List<SnChatMember>> chatroomInvites(Ref ref) async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get('/sphere/chat/invites');
|
||||
final resp = await client.get('/messager/chat/invites');
|
||||
return resp.data
|
||||
.map((e) => SnChatMember.fromJson(e))
|
||||
.cast<SnChatMember>()
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'chat_room.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ChatRoomJoinedNotifier)
|
||||
const chatRoomJoinedProvider = ChatRoomJoinedNotifierProvider._();
|
||||
final chatRoomJoinedProvider = ChatRoomJoinedNotifierProvider._();
|
||||
|
||||
final class ChatRoomJoinedNotifierProvider
|
||||
extends $AsyncNotifierProvider<ChatRoomJoinedNotifier, List<SnChatRoom>> {
|
||||
const ChatRoomJoinedNotifierProvider._()
|
||||
ChatRoomJoinedNotifierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -34,7 +34,7 @@ final class ChatRoomJoinedNotifierProvider
|
||||
}
|
||||
|
||||
String _$chatRoomJoinedNotifierHash() =>
|
||||
r'e69955be56ef2c04a8062a8a65925e0a23bfcbaa';
|
||||
r'b3726e10298b99a8529c5e28a5c402b95016f096';
|
||||
|
||||
abstract class _$ChatRoomJoinedNotifier
|
||||
extends $AsyncNotifier<List<SnChatRoom>> {
|
||||
@@ -42,7 +42,6 @@ abstract class _$ChatRoomJoinedNotifier
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref =
|
||||
this.ref as $Ref<AsyncValue<List<SnChatRoom>>, List<SnChatRoom>>;
|
||||
final element =
|
||||
@@ -53,16 +52,16 @@ abstract class _$ChatRoomJoinedNotifier
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(ChatRoomNotifier)
|
||||
const chatRoomProvider = ChatRoomNotifierFamily._();
|
||||
final chatRoomProvider = ChatRoomNotifierFamily._();
|
||||
|
||||
final class ChatRoomNotifierProvider
|
||||
extends $AsyncNotifierProvider<ChatRoomNotifier, SnChatRoom?> {
|
||||
const ChatRoomNotifierProvider._({
|
||||
ChatRoomNotifierProvider._({
|
||||
required ChatRoomNotifierFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -98,7 +97,7 @@ final class ChatRoomNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$chatRoomNotifierHash() => r'1e6391e2ab4eeb114fa001aaa6b06ab2bd646f38';
|
||||
String _$chatRoomNotifierHash() => r'9f7a8bdd4af381c6b60e65e74363a0af3c1a650e';
|
||||
|
||||
final class ChatRoomNotifierFamily extends $Family
|
||||
with
|
||||
@@ -109,7 +108,7 @@ final class ChatRoomNotifierFamily extends $Family
|
||||
FutureOr<SnChatRoom?>,
|
||||
String?
|
||||
> {
|
||||
const ChatRoomNotifierFamily._()
|
||||
ChatRoomNotifierFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'chatRoomProvider',
|
||||
@@ -133,7 +132,6 @@ abstract class _$ChatRoomNotifier extends $AsyncNotifier<SnChatRoom?> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args);
|
||||
final ref = this.ref as $Ref<AsyncValue<SnChatRoom?>, SnChatRoom?>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -143,16 +141,16 @@ abstract class _$ChatRoomNotifier extends $AsyncNotifier<SnChatRoom?> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(ChatRoomIdentityNotifier)
|
||||
const chatRoomIdentityProvider = ChatRoomIdentityNotifierFamily._();
|
||||
final chatRoomIdentityProvider = ChatRoomIdentityNotifierFamily._();
|
||||
|
||||
final class ChatRoomIdentityNotifierProvider
|
||||
extends $AsyncNotifierProvider<ChatRoomIdentityNotifier, SnChatMember?> {
|
||||
const ChatRoomIdentityNotifierProvider._({
|
||||
ChatRoomIdentityNotifierProvider._({
|
||||
required ChatRoomIdentityNotifierFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -190,7 +188,7 @@ final class ChatRoomIdentityNotifierProvider
|
||||
}
|
||||
|
||||
String _$chatRoomIdentityNotifierHash() =>
|
||||
r'27c17d55366d39be81d7209837e5c01f80a68a24';
|
||||
r'1ce75462a19cc037c97ee6084a30fee1f5335875';
|
||||
|
||||
final class ChatRoomIdentityNotifierFamily extends $Family
|
||||
with
|
||||
@@ -201,7 +199,7 @@ final class ChatRoomIdentityNotifierFamily extends $Family
|
||||
FutureOr<SnChatMember?>,
|
||||
String?
|
||||
> {
|
||||
const ChatRoomIdentityNotifierFamily._()
|
||||
ChatRoomIdentityNotifierFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'chatRoomIdentityProvider',
|
||||
@@ -226,7 +224,6 @@ abstract class _$ChatRoomIdentityNotifier
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args);
|
||||
final ref = this.ref as $Ref<AsyncValue<SnChatMember?>, SnChatMember?>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -236,12 +233,12 @@ abstract class _$ChatRoomIdentityNotifier
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(chatroomInvites)
|
||||
const chatroomInvitesProvider = ChatroomInvitesProvider._();
|
||||
final chatroomInvitesProvider = ChatroomInvitesProvider._();
|
||||
|
||||
final class ChatroomInvitesProvider
|
||||
extends
|
||||
@@ -253,7 +250,7 @@ final class ChatroomInvitesProvider
|
||||
with
|
||||
$FutureModifier<List<SnChatMember>>,
|
||||
$FutureProvider<List<SnChatMember>> {
|
||||
const ChatroomInvitesProvider._()
|
||||
ChatroomInvitesProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -279,4 +276,4 @@ final class ChatroomInvitesProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
|
||||
String _$chatroomInvitesHash() => r'fc23231d5f111b1c3796ffae2b471384b951861a';
|
||||
|
||||
@@ -7,6 +7,7 @@ import "package:island/pods/chat/chat_room.dart";
|
||||
import "package:island/pods/lifecycle.dart";
|
||||
import "package:island/pods/chat/messages_notifier.dart";
|
||||
import "package:island/pods/websocket.dart";
|
||||
import "package:island/talker.dart";
|
||||
import "package:island/widgets/chat/call_button.dart";
|
||||
import "package:riverpod_annotation/riverpod_annotation.dart";
|
||||
|
||||
@@ -35,6 +36,22 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||
Timer? _typingCooldownTimer;
|
||||
Timer? _periodicSubscribeTimer;
|
||||
StreamSubscription? _wsSubscription;
|
||||
Function? _sendMessage;
|
||||
|
||||
void _cleanupResources() {
|
||||
if (_wsSubscription != null) {
|
||||
_wsSubscription!.cancel();
|
||||
_wsSubscription = null;
|
||||
}
|
||||
if (_typingCleanupTimer != null) {
|
||||
_typingCleanupTimer!.cancel();
|
||||
_typingCleanupTimer = null;
|
||||
}
|
||||
if (_periodicSubscribeTimer != null) {
|
||||
_periodicSubscribeTimer!.cancel();
|
||||
_periodicSubscribeTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<SnChatMember> build(String roomId) {
|
||||
@@ -43,6 +60,8 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||
final chatIdentityAsync = ref.watch(chatRoomIdentityProvider(roomId));
|
||||
_messagesNotifier = ref.watch(messagesProvider(roomId).notifier);
|
||||
|
||||
_cleanupResources();
|
||||
|
||||
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
|
||||
return [];
|
||||
}
|
||||
@@ -56,12 +75,14 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||
|
||||
// Subscribe to messages
|
||||
final wsState = ref.read(websocketStateProvider.notifier);
|
||||
wsState.sendMessage(
|
||||
_sendMessage = wsState.sendMessage;
|
||||
talker.info('[MessageSubscriber] Subscribing room $roomId');
|
||||
_sendMessage!(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.subscribe',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'sphere',
|
||||
endpoint: 'messager',
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -93,64 +114,85 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||
|
||||
// Set up periodic subscribe timer (every 5 minutes)
|
||||
_periodicSubscribeTimer = Timer.periodic(const Duration(minutes: 5), (_) {
|
||||
wsState.sendMessage(
|
||||
_sendMessage!(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.subscribe',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'sphere',
|
||||
endpoint: 'messager',
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
// Listen to app lifecycle changes
|
||||
ref.listen(appLifecycleStateProvider, (previous, next) {
|
||||
final lifecycleState = next.value;
|
||||
if (lifecycleState == AppLifecycleState.paused ||
|
||||
lifecycleState == AppLifecycleState.inactive) {
|
||||
// Unsubscribe when app goes to background
|
||||
final wsState = ref.read(websocketStateProvider.notifier);
|
||||
wsState.sendMessage(
|
||||
talker.info('[MessageSubscriber] Unsubscribing room $roomId');
|
||||
_sendMessage!(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.unsubscribe',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'sphere',
|
||||
endpoint: 'messager',
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (lifecycleState == AppLifecycleState.resumed) {
|
||||
// Resubscribe when app comes back to foreground
|
||||
final wsState = ref.read(websocketStateProvider.notifier);
|
||||
wsState.sendMessage(
|
||||
talker.info('[MessageSubscriber] Subscribing room $roomId');
|
||||
_sendMessage!(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.subscribe',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'sphere',
|
||||
endpoint: 'messager',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup on dispose
|
||||
ref.onDispose(() {
|
||||
ref.read(currentSubscribedChatIdProvider.notifier).set(null);
|
||||
wsState.sendMessage(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.unsubscribe',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'sphere',
|
||||
final subscribedNotifier = ref.watch(
|
||||
currentSubscribedChatIdProvider.notifier,
|
||||
);
|
||||
|
||||
ref.onCancel(() {
|
||||
talker.info('[MessageSubscriber] Unsubscribing room $roomId');
|
||||
subscribedNotifier.set(null);
|
||||
try {
|
||||
_sendMessage!(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.unsubscribe',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'messager',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
_wsSubscription?.cancel();
|
||||
_typingCleanupTimer?.cancel();
|
||||
_typingCooldownTimer?.cancel();
|
||||
_periodicSubscribeTimer?.cancel();
|
||||
);
|
||||
} catch (e, stackTrace) {
|
||||
talker.error(
|
||||
'[MessageSubscriber] Error sending unsubscribe message for room $roomId: $e\n$stackTrace',
|
||||
);
|
||||
}
|
||||
try {
|
||||
_cleanupResources();
|
||||
} catch (e, stackTrace) {
|
||||
talker.error(
|
||||
'[MessageSubscriber] Error during cleanup for room $roomId: $e\n$stackTrace',
|
||||
);
|
||||
}
|
||||
try {
|
||||
if (_typingCooldownTimer != null) {
|
||||
_typingCooldownTimer!.cancel();
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
talker.error(
|
||||
'[MessageSubscriber] Error cancelling typing cooldown timer for room $roomId: $e\n$stackTrace',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return _typingStatuses;
|
||||
@@ -201,13 +243,13 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||
|
||||
void sendReadReceipt() {
|
||||
// Send websocket packet
|
||||
final wsState = ref.read(websocketStateProvider.notifier);
|
||||
wsState.sendMessage(
|
||||
if (_sendMessage == null) return;
|
||||
_sendMessage!(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.read',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'sphere',
|
||||
endpoint: 'messager',
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -218,13 +260,13 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||
if (_typingCooldownTimer != null) return;
|
||||
|
||||
// Send typing status immediately
|
||||
final wsState = ref.read(websocketStateProvider.notifier);
|
||||
wsState.sendMessage(
|
||||
if (_sendMessage == null) return;
|
||||
_sendMessage!(
|
||||
jsonEncode(
|
||||
WebSocketPacket(
|
||||
type: 'messages.typing',
|
||||
data: {'chat_room_id': roomId},
|
||||
endpoint: 'sphere',
|
||||
endpoint: 'messager',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'chat_subscribe.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ChatSubscribeNotifier)
|
||||
const chatSubscribeProvider = ChatSubscribeNotifierFamily._();
|
||||
final chatSubscribeProvider = ChatSubscribeNotifierFamily._();
|
||||
|
||||
final class ChatSubscribeNotifierProvider
|
||||
extends $NotifierProvider<ChatSubscribeNotifier, List<SnChatMember>> {
|
||||
const ChatSubscribeNotifierProvider._({
|
||||
ChatSubscribeNotifierProvider._({
|
||||
required ChatSubscribeNotifierFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -59,7 +59,7 @@ final class ChatSubscribeNotifierProvider
|
||||
}
|
||||
|
||||
String _$chatSubscribeNotifierHash() =>
|
||||
r'1aa164429aaab1628b5edbae11e33b0860abdcdc';
|
||||
r'b7624ae45ace2944a88f8b4d14ddce556c236371';
|
||||
|
||||
final class ChatSubscribeNotifierFamily extends $Family
|
||||
with
|
||||
@@ -70,7 +70,7 @@ final class ChatSubscribeNotifierFamily extends $Family
|
||||
List<SnChatMember>,
|
||||
String
|
||||
> {
|
||||
const ChatSubscribeNotifierFamily._()
|
||||
ChatSubscribeNotifierFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'chatSubscribeProvider',
|
||||
@@ -94,7 +94,6 @@ abstract class _$ChatSubscribeNotifier extends $Notifier<List<SnChatMember>> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args);
|
||||
final ref = this.ref as $Ref<List<SnChatMember>, List<SnChatMember>>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -104,6 +103,6 @@ abstract class _$ChatSubscribeNotifier extends $Notifier<List<SnChatMember>> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class ChatUnreadCountNotifier extends _$ChatUnreadCountNotifier {
|
||||
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final response = await client.get('/sphere/chat/unread');
|
||||
final response = await client.get('/messager/chat/unread');
|
||||
return (response.data as num).toInt();
|
||||
} catch (_) {
|
||||
return 0;
|
||||
@@ -65,7 +65,7 @@ class ChatSummary extends _$ChatSummary {
|
||||
@override
|
||||
Future<Map<String, SnChatSummary>> build() async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get('/sphere/chat/summary');
|
||||
final resp = await client.get('/messager/chat/summary');
|
||||
|
||||
final Map<String, dynamic> data = resp.data;
|
||||
final summaries = data.map(
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'chat_summary.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ChatUnreadCountNotifier)
|
||||
const chatUnreadCountProvider = ChatUnreadCountNotifierProvider._();
|
||||
final chatUnreadCountProvider = ChatUnreadCountNotifierProvider._();
|
||||
|
||||
final class ChatUnreadCountNotifierProvider
|
||||
extends $AsyncNotifierProvider<ChatUnreadCountNotifier, int> {
|
||||
const ChatUnreadCountNotifierProvider._()
|
||||
ChatUnreadCountNotifierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -34,14 +34,13 @@ final class ChatUnreadCountNotifierProvider
|
||||
}
|
||||
|
||||
String _$chatUnreadCountNotifierHash() =>
|
||||
r'b8d93589dc37f772d4c3a07d9afd81c37026e57d';
|
||||
r'169b28f8759ebd9de75f7de17f60d493737ee7a8';
|
||||
|
||||
abstract class _$ChatUnreadCountNotifier extends $AsyncNotifier<int> {
|
||||
FutureOr<int> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<AsyncValue<int>, int>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -51,16 +50,16 @@ abstract class _$ChatUnreadCountNotifier extends $AsyncNotifier<int> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(ChatSummary)
|
||||
const chatSummaryProvider = ChatSummaryProvider._();
|
||||
final chatSummaryProvider = ChatSummaryProvider._();
|
||||
|
||||
final class ChatSummaryProvider
|
||||
extends $AsyncNotifierProvider<ChatSummary, Map<String, SnChatSummary>> {
|
||||
const ChatSummaryProvider._()
|
||||
ChatSummaryProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -79,7 +78,7 @@ final class ChatSummaryProvider
|
||||
ChatSummary create() => ChatSummary();
|
||||
}
|
||||
|
||||
String _$chatSummaryHash() => r'dfa5e487586482ebdafef8d711f74db68ee86f84';
|
||||
String _$chatSummaryHash() => r'82f516d4ce8b67dadb815523df57a3c30a33ef91';
|
||||
|
||||
abstract class _$ChatSummary
|
||||
extends $AsyncNotifier<Map<String, SnChatSummary>> {
|
||||
@@ -87,7 +86,6 @@ abstract class _$ChatSummary
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<
|
||||
@@ -105,6 +103,6 @@ abstract class _$ChatSummary
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import "package:island/screens/account/profile.dart";
|
||||
|
||||
part 'messages_notifier.g.dart';
|
||||
|
||||
const Set<String> kSilentMessageTypes = {'messages.update.links'};
|
||||
|
||||
@riverpod
|
||||
class MessagesNotifier extends _$MessagesNotifier {
|
||||
late Dio _apiClient;
|
||||
@@ -48,6 +50,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
|
||||
late Future<SnAccount?> Function(String) _fetchAccount;
|
||||
|
||||
// Disposal handling
|
||||
bool _disposed = false;
|
||||
|
||||
@override
|
||||
FutureOr<List<LocalChatMessage>> build(String roomId) async {
|
||||
_apiClient = ref.watch(apiClientProvider);
|
||||
@@ -76,10 +81,17 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
|
||||
talker.log('MessagesNotifier built for room $roomId');
|
||||
|
||||
// Set up disposal handling
|
||||
ref.onDispose(() {
|
||||
_disposed = true;
|
||||
talker.log('MessagesNotifier disposed for room $roomId');
|
||||
});
|
||||
|
||||
// Only setup sync and lifecycle listeners if user is a member
|
||||
if (identity != null) {
|
||||
ref.listen(appLifecycleStateProvider, (_, next) {
|
||||
next.whenData((state) {
|
||||
if (_disposed) return; // Check disposal before accessing ref
|
||||
if (state == AppLifecycleState.paused) {
|
||||
_lastPauseTime = DateTime.now();
|
||||
talker.log('App paused, recording time');
|
||||
@@ -88,7 +100,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
final diff = DateTime.now().difference(_lastPauseTime!);
|
||||
if (diff > const Duration(minutes: 1)) {
|
||||
talker.log('App resumed after >1 min, syncing messages');
|
||||
syncMessages();
|
||||
if (!_disposed) {
|
||||
syncMessages(); // Check disposal before calling syncMessages
|
||||
}
|
||||
} else {
|
||||
talker.log('App resumed within 1 min, skipping sync');
|
||||
}
|
||||
@@ -167,15 +181,15 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
List<LocalChatMessage> filteredMessages = dbMessages;
|
||||
|
||||
if (withLinks == true) {
|
||||
filteredMessages =
|
||||
filteredMessages.where((msg) => _hasLink(msg)).toList();
|
||||
filteredMessages = filteredMessages
|
||||
.where((msg) => _hasLink(msg))
|
||||
.toList();
|
||||
}
|
||||
|
||||
if (withAttachments == true) {
|
||||
filteredMessages =
|
||||
filteredMessages
|
||||
.where((msg) => msg.toRemoteMessage().attachments.isNotEmpty)
|
||||
.toList();
|
||||
filteredMessages = filteredMessages
|
||||
.where((msg) => msg.toRemoteMessage().attachments.isNotEmpty)
|
||||
.toList();
|
||||
}
|
||||
|
||||
final dbLocalMessages = filteredMessages;
|
||||
@@ -190,8 +204,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
final pendingForRoom =
|
||||
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
||||
final pendingForRoom = _pendingMessages.values
|
||||
.where((msg) => msg.roomId == roomId)
|
||||
.toList();
|
||||
|
||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||
_sortMessages(allMessages); // Use the helper function
|
||||
@@ -239,8 +254,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
final pendingForRoom =
|
||||
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
||||
final pendingForRoom = _pendingMessages.values
|
||||
.where((msg) => msg.roomId == roomId)
|
||||
.toList();
|
||||
|
||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||
_sortMessages(allMessages);
|
||||
@@ -265,7 +281,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
talker.log('Fetching messages from API, offset $offset, take $take');
|
||||
if (_totalCount == null) {
|
||||
final response = await _apiClient.get(
|
||||
'/sphere/chat/$roomId/messages',
|
||||
'/messager/chat/$roomId/messages',
|
||||
queryParameters: {'offset': 0, 'take': 1},
|
||||
);
|
||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||
@@ -277,21 +293,20 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
}
|
||||
|
||||
final response = await _apiClient.get(
|
||||
'/sphere/chat/$roomId/messages',
|
||||
'/messager/chat/$roomId/messages',
|
||||
queryParameters: {'offset': offset, 'take': take},
|
||||
);
|
||||
|
||||
final List<dynamic> data = response.data;
|
||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||
|
||||
final messages =
|
||||
data.map((json) {
|
||||
final remoteMessage = SnChatMessage.fromJson(json);
|
||||
return LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
}).toList();
|
||||
final messages = data.map((json) {
|
||||
final remoteMessage = SnChatMessage.fromJson(json);
|
||||
return LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
for (final message in messages) {
|
||||
await _database.saveMessageWithSender(message);
|
||||
@@ -319,20 +334,24 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
_allRemoteMessagesFetched = false;
|
||||
|
||||
talker.log('Starting message sync');
|
||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(true));
|
||||
// Use Future.microtask to set syncing state, but check disposal to avoid errors
|
||||
Future.microtask(() {
|
||||
if (!_disposed) {
|
||||
ref.read(chatSyncingProvider.notifier).set(true);
|
||||
}
|
||||
});
|
||||
try {
|
||||
final dbMessages = await _database.getMessagesForRoom(
|
||||
_room.id,
|
||||
offset: 0,
|
||||
limit: 1,
|
||||
);
|
||||
final lastMessage =
|
||||
dbMessages.isEmpty
|
||||
? null
|
||||
: await _database.companionToMessage(
|
||||
dbMessages.first,
|
||||
fetchAccount: _fetchAccount,
|
||||
);
|
||||
final lastMessage = dbMessages.isEmpty
|
||||
? null
|
||||
: await _database.companionToMessage(
|
||||
dbMessages.first,
|
||||
fetchAccount: _fetchAccount,
|
||||
);
|
||||
|
||||
if (lastMessage == null) {
|
||||
talker.log('No local messages, fetching from network');
|
||||
@@ -347,12 +366,14 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
// Sync with pagination support using timestamp-based cursor
|
||||
int? totalMessages;
|
||||
int syncedCount = 0;
|
||||
int lastSyncTimestamp =
|
||||
lastMessage.toRemoteMessage().updatedAt.millisecondsSinceEpoch;
|
||||
int lastSyncTimestamp = lastMessage
|
||||
.toRemoteMessage()
|
||||
.updatedAt
|
||||
.millisecondsSinceEpoch;
|
||||
|
||||
do {
|
||||
final resp = await _apiClient.post(
|
||||
'/sphere/chat/${_room.id}/sync',
|
||||
'/messager/chat/${_room.id}/sync',
|
||||
data: {'last_sync_timestamp': lastSyncTimestamp},
|
||||
);
|
||||
|
||||
@@ -395,6 +416,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
talker.log('Finished message sync');
|
||||
// Always reset global syncing state, regardless of disposal
|
||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(false));
|
||||
_isSyncing = false;
|
||||
}
|
||||
@@ -492,7 +514,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
if (!_hasMore || state is AsyncLoading) return;
|
||||
talker.log('Loading more messages');
|
||||
|
||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(true));
|
||||
if (!_disposed) {
|
||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(true));
|
||||
}
|
||||
try {
|
||||
final currentMessages = state.value ?? [];
|
||||
final offset = currentMessages.length;
|
||||
@@ -515,6 +539,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
);
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
// Always reset global syncing state, regardless of disposal
|
||||
Future.microtask(() => ref.read(chatSyncingProvider.notifier).set(false));
|
||||
}
|
||||
}
|
||||
@@ -559,18 +584,17 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
try {
|
||||
var cloudAttachments = List.empty(growable: true);
|
||||
for (var idx = 0; idx < attachments.length; idx++) {
|
||||
final cloudFile =
|
||||
await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: attachments[idx],
|
||||
onProgress: (progress, _) {
|
||||
_fileUploadProgress[localMessage.id]?[idx] = progress ?? 0.0;
|
||||
onProgress?.call(
|
||||
localMessage.id,
|
||||
_fileUploadProgress[localMessage.id] ?? {},
|
||||
);
|
||||
},
|
||||
).future;
|
||||
final cloudFile = await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: attachments[idx],
|
||||
onProgress: (progress, _) {
|
||||
_fileUploadProgress[localMessage.id]?[idx] = progress ?? 0.0;
|
||||
onProgress?.call(
|
||||
localMessage.id,
|
||||
_fileUploadProgress[localMessage.id] ?? {},
|
||||
);
|
||||
},
|
||||
).future;
|
||||
if (cloudFile == null) {
|
||||
throw ArgumentError('Failed to upload the file...');
|
||||
}
|
||||
@@ -579,8 +603,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
|
||||
final response = await _apiClient.request(
|
||||
editingTo == null
|
||||
? '/sphere/chat/$roomId/messages'
|
||||
: '/sphere/chat/$roomId/messages/${editingTo.id}',
|
||||
? '/messager/chat/$roomId/messages'
|
||||
: '/messager/chat/$roomId/messages/${editingTo.id}',
|
||||
data: {
|
||||
'content': content,
|
||||
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
||||
@@ -606,22 +630,20 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
|
||||
final currentMessages = state.value ?? [];
|
||||
if (editingTo != null) {
|
||||
final newMessages =
|
||||
currentMessages
|
||||
.where((m) => m.id != localMessage.id) // remove pending message
|
||||
.map(
|
||||
(m) => m.id == editingTo.id ? updatedMessage : m,
|
||||
) // update original message
|
||||
.toList();
|
||||
final newMessages = currentMessages
|
||||
.where((m) => m.id != localMessage.id) // remove pending message
|
||||
.map(
|
||||
(m) => m.id == editingTo.id ? updatedMessage : m,
|
||||
) // update original message
|
||||
.toList();
|
||||
state = AsyncValue.data(newMessages);
|
||||
} else {
|
||||
final newMessages =
|
||||
currentMessages.map((m) {
|
||||
if (m.id == localMessage.id) {
|
||||
return updatedMessage;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
final newMessages = currentMessages.map((m) {
|
||||
if (m.id == localMessage.id) {
|
||||
return updatedMessage;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
state = AsyncValue.data(newMessages);
|
||||
}
|
||||
talker.log('Message with nonce $nonce sent successfully');
|
||||
@@ -638,13 +660,12 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
localMessage.id,
|
||||
MessageStatus.failed,
|
||||
);
|
||||
final newMessages =
|
||||
(state.value ?? []).map((m) {
|
||||
if (m.id == localMessage.id) {
|
||||
return m..status = MessageStatus.failed;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
final newMessages = (state.value ?? []).map((m) {
|
||||
if (m.id == localMessage.id) {
|
||||
return m..status = MessageStatus.failed;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
state = AsyncValue.data(newMessages);
|
||||
showErrorAlert(e);
|
||||
}
|
||||
@@ -667,7 +688,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
try {
|
||||
var remoteMessage = message.toRemoteMessage();
|
||||
final response = await _apiClient.post(
|
||||
'/sphere/chat/${message.roomId}/messages',
|
||||
'/messager/chat/${message.roomId}/messages',
|
||||
data: {
|
||||
'content': remoteMessage.content,
|
||||
'attachments_id': remoteMessage.attachments,
|
||||
@@ -686,13 +707,12 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
await _database.deleteMessage(pendingMessageId);
|
||||
await _database.saveMessageWithSender(updatedMessage);
|
||||
|
||||
final newMessages =
|
||||
(state.value ?? []).map((m) {
|
||||
if (m.id == pendingMessageId) {
|
||||
return updatedMessage;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
final newMessages = (state.value ?? []).map((m) {
|
||||
if (m.id == pendingMessageId) {
|
||||
return updatedMessage;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
state = AsyncValue.data(newMessages);
|
||||
} catch (e, stackTrace) {
|
||||
talker.log(
|
||||
@@ -707,13 +727,12 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
pendingMessageId,
|
||||
MessageStatus.failed,
|
||||
);
|
||||
final newMessages =
|
||||
(state.value ?? []).map((m) {
|
||||
if (m.id == pendingMessageId) {
|
||||
return m..status = MessageStatus.failed;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
final newMessages = (state.value ?? []).map((m) {
|
||||
if (m.id == pendingMessageId) {
|
||||
return m..status = MessageStatus.failed;
|
||||
}
|
||||
return m;
|
||||
}).toList();
|
||||
state = AsyncValue.data(_sortMessages(newMessages));
|
||||
showErrorAlert(e);
|
||||
}
|
||||
@@ -730,6 +749,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
|
||||
talker.log('Received new message ${remoteMessage.id}');
|
||||
|
||||
final isSilentMessage = kSilentMessageTypes.contains(remoteMessage.type);
|
||||
|
||||
final localMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
@@ -741,23 +762,25 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
);
|
||||
}
|
||||
|
||||
await _database.saveMessageWithSender(localMessage);
|
||||
if (!isSilentMessage) {
|
||||
await _database.saveMessageWithSender(localMessage);
|
||||
|
||||
final currentMessages = state.value ?? [];
|
||||
final existingIndex = currentMessages.indexWhere(
|
||||
(m) =>
|
||||
m.id == localMessage.id ||
|
||||
(localMessage.nonce != null && m.nonce == localMessage.nonce),
|
||||
);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
final newList = [...currentMessages];
|
||||
newList[existingIndex] = localMessage;
|
||||
state = AsyncValue.data(_sortMessages(newList));
|
||||
} else {
|
||||
state = AsyncValue.data(
|
||||
_sortMessages([localMessage, ...currentMessages]),
|
||||
final currentMessages = state.value ?? [];
|
||||
final existingIndex = currentMessages.indexWhere(
|
||||
(m) =>
|
||||
m.id == localMessage.id ||
|
||||
(localMessage.nonce != null && m.nonce == localMessage.nonce),
|
||||
);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
final newList = [...currentMessages];
|
||||
newList[existingIndex] = localMessage;
|
||||
state = AsyncValue.data(_sortMessages(newList));
|
||||
} else {
|
||||
state = AsyncValue.data(
|
||||
_sortMessages([localMessage, ...currentMessages]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
switch (remoteMessage.type) {
|
||||
@@ -783,15 +806,44 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
talker.log('Received message update ${remoteMessage.id}');
|
||||
|
||||
final targetId = remoteMessage.meta['message_id'] ?? remoteMessage.id;
|
||||
final updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage.copyWith(
|
||||
id: targetId,
|
||||
meta: Map.of(remoteMessage.meta)..remove('message_id'),
|
||||
type: 'text',
|
||||
|
||||
LocalChatMessage updatedMessage;
|
||||
|
||||
if (remoteMessage.type == 'messages.update.links') {
|
||||
// For link updates, merge meta with existing message instead of creating new one
|
||||
final existingMessage = await fetchMessageById(targetId);
|
||||
if (existingMessage == null) {
|
||||
talker.log('Cannot update links for non-existent message $targetId');
|
||||
return;
|
||||
}
|
||||
|
||||
final existingRemote = existingMessage.toRemoteMessage();
|
||||
final mergedMeta = Map<String, dynamic>.of(existingRemote.meta);
|
||||
mergedMeta.addAll(remoteMessage.meta);
|
||||
mergedMeta.remove('message_id'); // Remove the target message ID from meta
|
||||
|
||||
final updatedRemote = existingRemote.copyWith(
|
||||
meta: mergedMeta,
|
||||
editedAt: remoteMessage.createdAt,
|
||||
),
|
||||
MessageStatus.sent,
|
||||
);
|
||||
);
|
||||
|
||||
updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||
updatedRemote,
|
||||
existingMessage.status,
|
||||
);
|
||||
} else {
|
||||
// For regular updates, create new message as before
|
||||
updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage.copyWith(
|
||||
id: targetId,
|
||||
meta: Map.of(remoteMessage.meta)..remove('message_id'),
|
||||
type: 'text',
|
||||
editedAt: remoteMessage.createdAt,
|
||||
),
|
||||
MessageStatus.sent,
|
||||
);
|
||||
}
|
||||
|
||||
await _database.updateMessage(_database.messageToCompanion(updatedMessage));
|
||||
|
||||
final currentMessages = state.value ?? [];
|
||||
@@ -865,14 +917,15 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
await _database.deleteMessage(messageId);
|
||||
|
||||
final currentMessages = state.value ?? [];
|
||||
final newMessages =
|
||||
currentMessages.where((m) => m.id != messageId).toList();
|
||||
final newMessages = currentMessages
|
||||
.where((m) => m.id != messageId)
|
||||
.toList();
|
||||
state = AsyncValue.data(newMessages);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await _apiClient.delete('/sphere/chat/$roomId/messages/$messageId');
|
||||
await _apiClient.delete('/messager/chat/$roomId/messages/$messageId');
|
||||
await receiveMessageDeletion(messageId);
|
||||
} catch (err, stackTrace) {
|
||||
talker.log(
|
||||
@@ -969,9 +1022,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
Future<LocalChatMessage?> fetchMessageById(String messageId) async {
|
||||
talker.log('Fetching message by id $messageId');
|
||||
try {
|
||||
final localMessage =
|
||||
await (_database.select(_database.chatMessages)
|
||||
..where((tbl) => tbl.id.equals(messageId))).getSingleOrNull();
|
||||
final localMessage = await (_database.select(
|
||||
_database.chatMessages,
|
||||
)..where((tbl) => tbl.id.equals(messageId))).getSingleOrNull();
|
||||
if (localMessage != null) {
|
||||
return _database.companionToMessage(
|
||||
localMessage,
|
||||
@@ -980,7 +1033,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
}
|
||||
|
||||
final response = await _apiClient.get(
|
||||
'/sphere/chat/$roomId/messages/$messageId',
|
||||
'/messager/chat/$roomId/messages/$messageId',
|
||||
);
|
||||
final remoteMessage = SnChatMessage.fromJson(response.data);
|
||||
final message = LocalChatMessage.fromRemoteMessage(
|
||||
@@ -1005,7 +1058,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
_isJumping = true;
|
||||
|
||||
// Clear flashing messages when starting a new jump
|
||||
ref.read(flashingMessagesProvider.notifier).state = {};
|
||||
if (!_disposed) {
|
||||
ref.read(flashingMessagesProvider.notifier).state = {};
|
||||
}
|
||||
|
||||
try {
|
||||
talker.log('Fetching message $messageId');
|
||||
@@ -1047,8 +1102,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
|
||||
// Calculate offset to position target message in the middle of the loaded chunk
|
||||
const chunkSize = 100; // Load 100 messages around the target
|
||||
final offset =
|
||||
(newerCount - chunkSize ~/ 2).clamp(0, double.infinity).toInt();
|
||||
final offset = (newerCount - chunkSize ~/ 2)
|
||||
.clamp(0, double.infinity)
|
||||
.toInt();
|
||||
talker.log(
|
||||
'Calculated offset $offset for target message (newer: $newerCount, chunk: $chunkSize)',
|
||||
);
|
||||
@@ -1060,8 +1116,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
||||
|
||||
// Check if loaded messages are already in current state
|
||||
final currentIds = currentMessages.map((m) => m.id).toSet();
|
||||
final newMessages =
|
||||
loadedMessages.where((m) => !currentIds.contains(m.id)).toList();
|
||||
final newMessages = loadedMessages
|
||||
.where((m) => !currentIds.contains(m.id))
|
||||
.toList();
|
||||
talker.log(
|
||||
'Loaded ${loadedMessages.length} messages, ${newMessages.length} are new',
|
||||
);
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'messages_notifier.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(MessagesNotifier)
|
||||
const messagesProvider = MessagesNotifierFamily._();
|
||||
final messagesProvider = MessagesNotifierFamily._();
|
||||
|
||||
final class MessagesNotifierProvider
|
||||
extends $AsyncNotifierProvider<MessagesNotifier, List<LocalChatMessage>> {
|
||||
const MessagesNotifierProvider._({
|
||||
MessagesNotifierProvider._({
|
||||
required MessagesNotifierFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -50,7 +50,7 @@ final class MessagesNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$messagesNotifierHash() => r'2f3f19cb99357184e82d66e74a31863fcfc48856';
|
||||
String _$messagesNotifierHash() => r'a721a4b92b48ee7c2289cdcd7130bbf1ca9dcb40';
|
||||
|
||||
final class MessagesNotifierFamily extends $Family
|
||||
with
|
||||
@@ -61,7 +61,7 @@ final class MessagesNotifierFamily extends $Family
|
||||
FutureOr<List<LocalChatMessage>>,
|
||||
String
|
||||
> {
|
||||
const MessagesNotifierFamily._()
|
||||
MessagesNotifierFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'messagesProvider',
|
||||
@@ -86,7 +86,6 @@ abstract class _$MessagesNotifier
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args);
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<AsyncValue<List<LocalChatMessage>>, List<LocalChatMessage>>;
|
||||
@@ -101,6 +100,6 @@ abstract class _$MessagesNotifier
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ const kAppDefaultPoolId = 'app_default_pool_id';
|
||||
const kAppMessageDisplayStyle = 'app_message_display_style';
|
||||
const kAppThemeMode = 'app_theme_mode';
|
||||
const kAppDisableAnimation = 'app_disable_animation';
|
||||
const kAppFabPosition = 'app_fab_position';
|
||||
const kAppGroupedChatList = 'app_grouped_chat_list';
|
||||
const kFeaturedPostsCollapsedId =
|
||||
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
||||
@@ -41,6 +40,7 @@ const kAppFirstLaunchAt = 'app_first_launch_at';
|
||||
const kAppAskedReview = 'app_asked_review';
|
||||
const kAppDashSearchEngine = 'app_dash_search_engine';
|
||||
const kAppDefaultScreen = 'app_default_screen';
|
||||
const kAppShowFediverseContent = 'app_show_fediverse_content';
|
||||
|
||||
// Will be overrided by the ProviderScope
|
||||
final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
|
||||
@@ -87,12 +87,12 @@ sealed class AppSettings with _$AppSettings {
|
||||
required String messageDisplayStyle,
|
||||
required String? themeMode,
|
||||
required bool disableAnimation,
|
||||
required String fabPosition,
|
||||
required bool groupedChatList,
|
||||
required String? firstLaunchAt,
|
||||
required bool askedReview,
|
||||
required String? dashSearchEngine,
|
||||
required String? defaultScreen,
|
||||
required bool showFediverseContent,
|
||||
}) = _AppSettings;
|
||||
}
|
||||
|
||||
@@ -119,12 +119,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
||||
messageDisplayStyle: prefs.getString(kAppMessageDisplayStyle) ?? 'bubble',
|
||||
themeMode: prefs.getString(kAppThemeMode) ?? 'system',
|
||||
disableAnimation: prefs.getBool(kAppDisableAnimation) ?? false,
|
||||
fabPosition: prefs.getString(kAppFabPosition) ?? 'center',
|
||||
groupedChatList: prefs.getBool(kAppGroupedChatList) ?? false,
|
||||
askedReview: prefs.getBool(kAppAskedReview) ?? false,
|
||||
firstLaunchAt: prefs.getString(kAppFirstLaunchAt),
|
||||
dashSearchEngine: prefs.getString(kAppDashSearchEngine),
|
||||
defaultScreen: prefs.getString(kAppDefaultScreen),
|
||||
showFediverseContent: prefs.getBool(kAppShowFediverseContent) ?? true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -283,12 +283,6 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
||||
state = state.copyWith(disableAnimation: value);
|
||||
}
|
||||
|
||||
void setFabPosition(String value) {
|
||||
final prefs = ref.read(sharedPreferencesProvider);
|
||||
prefs.setString(kAppFabPosition, value);
|
||||
state = state.copyWith(fabPosition: value);
|
||||
}
|
||||
|
||||
void setGroupedChatList(bool value) {
|
||||
final prefs = ref.read(sharedPreferencesProvider);
|
||||
prefs.setBool(kAppGroupedChatList, value);
|
||||
@@ -320,6 +314,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
||||
}
|
||||
state = state.copyWith(dashSearchEngine: value);
|
||||
}
|
||||
|
||||
void setShowFediverseContent(bool value) {
|
||||
final prefs = ref.read(sharedPreferencesProvider);
|
||||
prefs.setBool(kAppShowFediverseContent, value);
|
||||
state = state.copyWith(showFediverseContent: value);
|
||||
}
|
||||
}
|
||||
|
||||
final updateInfoProvider =
|
||||
|
||||
@@ -290,7 +290,7 @@ mixin _$AppSettings {
|
||||
ThemeColors? get customColors; Size? get windowSize;// The window size for desktop platforms
|
||||
double get windowOpacity;// The window opacity for desktop platforms
|
||||
double get cardTransparency;// The card background opacity
|
||||
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get disableAnimation; String get fabPosition; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine; String? get defaultScreen;
|
||||
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get disableAnimation; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine; String? get defaultScreen; bool get showFediverseContent;
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -301,16 +301,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen)&&(identical(other.showFediverseContent, showFediverseContent) || other.showFediverseContent == showFediverseContent));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
|
||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen,showFediverseContent]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
|
||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen, showFediverseContent: $showFediverseContent)';
|
||||
}
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
|
||||
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
|
||||
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent
|
||||
});
|
||||
|
||||
|
||||
@@ -338,7 +338,7 @@ class _$AppSettingsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,Object? showFediverseContent = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
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
|
||||
@@ -357,13 +357,13 @@ as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaul
|
||||
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
||||
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
||||
as String?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
||||
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||
as bool,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
||||
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
||||
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
as String?,showFediverseContent: null == showFediverseContent ? _self.showFediverseContent : showFediverseContent // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
/// Create a copy of AppSettings
|
||||
@@ -457,10 +457,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettings() when $default != null:
|
||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
|
||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -478,10 +478,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettings():
|
||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);}
|
||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -495,10 +495,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettings() when $default != null:
|
||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
|
||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -510,7 +510,7 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
||||
|
||||
|
||||
class _AppSettings implements AppSettings {
|
||||
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.disableAnimation, required this.fabPosition, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine, required this.defaultScreen});
|
||||
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.disableAnimation, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine, required this.defaultScreen, required this.showFediverseContent});
|
||||
|
||||
|
||||
@override final bool dataSavingMode;
|
||||
@@ -534,12 +534,12 @@ class _AppSettings implements AppSettings {
|
||||
@override final String messageDisplayStyle;
|
||||
@override final String? themeMode;
|
||||
@override final bool disableAnimation;
|
||||
@override final String fabPosition;
|
||||
@override final bool groupedChatList;
|
||||
@override final String? firstLaunchAt;
|
||||
@override final bool askedReview;
|
||||
@override final String? dashSearchEngine;
|
||||
@override final String? defaultScreen;
|
||||
@override final bool showFediverseContent;
|
||||
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -551,16 +551,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen)&&(identical(other.showFediverseContent, showFediverseContent) || other.showFediverseContent == showFediverseContent));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
|
||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen,showFediverseContent]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
|
||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen, showFediverseContent: $showFediverseContent)';
|
||||
}
|
||||
|
||||
|
||||
@@ -571,7 +571,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
|
||||
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
|
||||
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent
|
||||
});
|
||||
|
||||
|
||||
@@ -588,7 +588,7 @@ class __$AppSettingsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,Object? showFediverseContent = null,}) {
|
||||
return _then(_AppSettings(
|
||||
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
|
||||
@@ -607,13 +607,13 @@ as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaul
|
||||
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
||||
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
||||
as String?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
||||
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||
as bool,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
||||
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
||||
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
as String?,showFediverseContent: null == showFediverseContent ? _self.showFediverseContent : showFediverseContent // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ Map<String, dynamic> _$ThemeColorsToJson(_ThemeColors instance) =>
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(AppSettingsNotifier)
|
||||
const appSettingsProvider = AppSettingsNotifierProvider._();
|
||||
final appSettingsProvider = AppSettingsNotifierProvider._();
|
||||
|
||||
final class AppSettingsNotifierProvider
|
||||
extends $NotifierProvider<AppSettingsNotifier, AppSettings> {
|
||||
const AppSettingsNotifierProvider._()
|
||||
AppSettingsNotifierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -65,14 +65,13 @@ final class AppSettingsNotifierProvider
|
||||
}
|
||||
|
||||
String _$appSettingsNotifierHash() =>
|
||||
r'ef10d95a9f22e891ad6f5e0225e31508b3eb038e';
|
||||
r'2437c621dcb1625a120ed1f21ab5c29906ba98be';
|
||||
|
||||
abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
|
||||
AppSettings build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<AppSettings, AppSettings>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -82,6 +81,6 @@ abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ final indexedCloudFileListProvider = AsyncNotifierProvider.autoDispose(
|
||||
IndexedCloudFileListNotifier.new,
|
||||
);
|
||||
|
||||
class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
||||
class IndexedCloudFileListNotifier
|
||||
extends AsyncNotifier<PaginationState<FileListItem>>
|
||||
with AsyncPaginationController<FileListItem> {
|
||||
String _currentPath = '/';
|
||||
String? _poolId;
|
||||
@@ -51,6 +52,19 @@ class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
||||
ref.invalidateSelf();
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<PaginationState<FileListItem>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: null,
|
||||
hasMore: false,
|
||||
cursor: null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<FileListItem>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
@@ -96,7 +110,8 @@ final unindexedFileListProvider = AsyncNotifierProvider.autoDispose(
|
||||
UnindexedFileListNotifier.new,
|
||||
);
|
||||
|
||||
class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
||||
class UnindexedFileListNotifier
|
||||
extends AsyncNotifier<PaginationState<FileListItem>>
|
||||
with AsyncPaginationController<FileListItem> {
|
||||
String? _poolId;
|
||||
bool _recycled = false;
|
||||
@@ -131,6 +146,19 @@ class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
|
||||
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
FutureOr<PaginationState<FileListItem>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<FileListItem>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'file_list.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(billingUsage)
|
||||
const billingUsageProvider = BillingUsageProvider._();
|
||||
final billingUsageProvider = BillingUsageProvider._();
|
||||
|
||||
final class BillingUsageProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class BillingUsageProvider
|
||||
with
|
||||
$FutureModifier<Map<String, dynamic>?>,
|
||||
$FutureProvider<Map<String, dynamic>?> {
|
||||
const BillingUsageProvider._()
|
||||
BillingUsageProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -51,7 +51,7 @@ final class BillingUsageProvider
|
||||
String _$billingUsageHash() => r'58d8bc774868d60781574c85d6b25869a79c57aa';
|
||||
|
||||
@ProviderFor(billingQuota)
|
||||
const billingQuotaProvider = BillingQuotaProvider._();
|
||||
final billingQuotaProvider = BillingQuotaProvider._();
|
||||
|
||||
final class BillingQuotaProvider
|
||||
extends
|
||||
@@ -63,7 +63,7 @@ final class BillingQuotaProvider
|
||||
with
|
||||
$FutureModifier<Map<String, dynamic>?>,
|
||||
$FutureProvider<Map<String, dynamic>?> {
|
||||
const BillingQuotaProvider._()
|
||||
BillingQuotaProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'file_references.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(fileReferences)
|
||||
const fileReferencesProvider = FileReferencesFamily._();
|
||||
final fileReferencesProvider = FileReferencesFamily._();
|
||||
|
||||
final class FileReferencesProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class FileReferencesProvider
|
||||
FutureOr<List<Reference>>
|
||||
>
|
||||
with $FutureModifier<List<Reference>>, $FutureProvider<List<Reference>> {
|
||||
const FileReferencesProvider._({
|
||||
FileReferencesProvider._({
|
||||
required FileReferencesFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -68,7 +68,7 @@ String _$fileReferencesHash() => r'd66c678c221f61978bdb242b98e6dbe31d0c204b';
|
||||
|
||||
final class FileReferencesFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<Reference>>, String> {
|
||||
const FileReferencesFamily._()
|
||||
FileReferencesFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'fileReferencesProvider',
|
||||
|
||||
@@ -12,7 +12,7 @@ part of 'event_calendar.dart';
|
||||
/// This can be used anywhere in the app where calendar data is needed
|
||||
|
||||
@ProviderFor(eventCalendar)
|
||||
const eventCalendarProvider = EventCalendarFamily._();
|
||||
final eventCalendarProvider = EventCalendarFamily._();
|
||||
|
||||
/// Provider for fetching event calendar data
|
||||
/// This can be used anywhere in the app where calendar data is needed
|
||||
@@ -29,7 +29,7 @@ final class EventCalendarProvider
|
||||
$FutureProvider<List<SnEventCalendarEntry>> {
|
||||
/// Provider for fetching event calendar data
|
||||
/// This can be used anywhere in the app where calendar data is needed
|
||||
const EventCalendarProvider._({
|
||||
EventCalendarProvider._({
|
||||
required EventCalendarFamily super.from,
|
||||
required EventCalendarQuery super.argument,
|
||||
}) : super(
|
||||
@@ -84,7 +84,7 @@ final class EventCalendarFamily extends $Family
|
||||
FutureOr<List<SnEventCalendarEntry>>,
|
||||
EventCalendarQuery
|
||||
> {
|
||||
const EventCalendarFamily._()
|
||||
EventCalendarFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'eventCalendarProvider',
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'link_preview.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(LinkPreview)
|
||||
const linkPreviewProvider = LinkPreviewFamily._();
|
||||
final linkPreviewProvider = LinkPreviewFamily._();
|
||||
|
||||
final class LinkPreviewProvider
|
||||
extends $AsyncNotifierProvider<LinkPreview, SnScrappedLink?> {
|
||||
const LinkPreviewProvider._({
|
||||
LinkPreviewProvider._({
|
||||
required LinkPreviewFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -61,7 +61,7 @@ final class LinkPreviewFamily extends $Family
|
||||
FutureOr<SnScrappedLink?>,
|
||||
String
|
||||
> {
|
||||
const LinkPreviewFamily._()
|
||||
LinkPreviewFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'linkPreviewProvider',
|
||||
@@ -85,7 +85,6 @@ abstract class _$LinkPreview extends $AsyncNotifier<SnScrappedLink?> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build(_$args);
|
||||
final ref = this.ref as $Ref<AsyncValue<SnScrappedLink?>, SnScrappedLink?>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -95,6 +94,6 @@ abstract class _$LinkPreview extends $AsyncNotifier<SnScrappedLink?> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,15 +152,7 @@ final apiClientProvider = Provider<Dio>((ref) {
|
||||
},
|
||||
onError: (error, handler) {
|
||||
// Handle network errors and set offline status
|
||||
if (error.type == DioExceptionType.connectionTimeout ||
|
||||
error.type == DioExceptionType.receiveTimeout ||
|
||||
error.type == DioExceptionType.sendTimeout ||
|
||||
error.type == DioExceptionType.connectionError) {
|
||||
final networkStatusNotifier = ref.read(
|
||||
networkStatusProvider.notifier,
|
||||
);
|
||||
networkStatusNotifier.setOffline();
|
||||
} else if (error.response?.statusCode == 503) {
|
||||
if (error.response?.statusCode == 503) {
|
||||
final networkStatusNotifier = ref.read(
|
||||
networkStatusProvider.notifier,
|
||||
);
|
||||
|
||||
@@ -10,11 +10,11 @@ part of 'network.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(NetworkStatusNotifier)
|
||||
const networkStatusProvider = NetworkStatusNotifierProvider._();
|
||||
final networkStatusProvider = NetworkStatusNotifierProvider._();
|
||||
|
||||
final class NetworkStatusNotifierProvider
|
||||
extends $NotifierProvider<NetworkStatusNotifier, NetworkStatus> {
|
||||
const NetworkStatusNotifierProvider._()
|
||||
NetworkStatusNotifierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -49,7 +49,6 @@ abstract class _$NetworkStatusNotifier extends $Notifier<NetworkStatus> {
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<NetworkStatus, NetworkStatus>;
|
||||
final element =
|
||||
ref.element
|
||||
@@ -59,6 +58,6 @@ abstract class _$NetworkStatusNotifier extends $Notifier<NetworkStatus> {
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,53 @@ import 'dart:async';
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
class PaginationState<T> {
|
||||
final List<T> items;
|
||||
final bool isLoading;
|
||||
final bool isReloading;
|
||||
final int? totalCount;
|
||||
final bool hasMore;
|
||||
final String? cursor;
|
||||
|
||||
const PaginationState({
|
||||
required this.items,
|
||||
required this.isLoading,
|
||||
required this.isReloading,
|
||||
required this.totalCount,
|
||||
required this.hasMore,
|
||||
required this.cursor,
|
||||
});
|
||||
|
||||
PaginationState<T> copyWith({
|
||||
List<T>? items,
|
||||
bool? isLoading,
|
||||
bool? isReloading,
|
||||
int? totalCount,
|
||||
bool? hasMore,
|
||||
String? cursor,
|
||||
}) {
|
||||
return PaginationState<T>(
|
||||
items: items ?? this.items,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
isReloading: isReloading ?? this.isReloading,
|
||||
totalCount: totalCount ?? this.totalCount,
|
||||
hasMore: hasMore ?? this.hasMore,
|
||||
cursor: cursor ?? this.cursor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PaginationController<T> {
|
||||
int? get totalCount;
|
||||
int get fetchedCount;
|
||||
|
||||
bool get fetchedAll;
|
||||
bool get isLoading;
|
||||
bool get isReloading;
|
||||
bool get hasMore;
|
||||
set hasMore(bool value);
|
||||
String? get cursor;
|
||||
set cursor(String? value);
|
||||
|
||||
FutureOr<List<T>> fetch();
|
||||
|
||||
@@ -22,50 +63,104 @@ abstract class PaginationFiltered<F> {
|
||||
Future<void> applyFilter(F filter);
|
||||
}
|
||||
|
||||
mixin AsyncPaginationController<T> on AsyncNotifier<List<T>>
|
||||
mixin AsyncPaginationController<T> on AsyncNotifier<PaginationState<T>>
|
||||
implements PaginationController<T> {
|
||||
@override
|
||||
int? totalCount;
|
||||
|
||||
@override
|
||||
int get fetchedCount => state.value?.length ?? 0;
|
||||
int get fetchedCount =>
|
||||
state.value?.isReloading == true ? 0 : state.value?.items.length ?? 0;
|
||||
|
||||
@override
|
||||
bool get fetchedAll => totalCount != null && fetchedCount >= totalCount!;
|
||||
bool get fetchedAll =>
|
||||
!(state.value?.hasMore ?? true) ||
|
||||
((state.value?.totalCount != null &&
|
||||
fetchedCount >= state.value!.totalCount!));
|
||||
|
||||
@override
|
||||
bool isLoading = false;
|
||||
bool get isLoading => state.value?.isLoading ?? false;
|
||||
|
||||
@override
|
||||
FutureOr<List<T>> build() async => fetch();
|
||||
bool get isReloading => state.value?.isReloading ?? false;
|
||||
|
||||
@override
|
||||
bool get hasMore => state.value?.hasMore ?? true;
|
||||
|
||||
@override
|
||||
String? get cursor => state.value?.cursor;
|
||||
|
||||
@override
|
||||
set hasMore(bool value) {
|
||||
if (state is AsyncData) {
|
||||
state = AsyncData((state as AsyncData).value.copyWith(hasMore: value));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
set cursor(String? value) {
|
||||
if (state is AsyncData) {
|
||||
state = AsyncData((state as AsyncData).value.copyWith(cursor: value));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<PaginationState<T>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> refresh() async {
|
||||
isLoading = true;
|
||||
totalCount = null;
|
||||
state = AsyncData<List<T>>([]);
|
||||
state = AsyncData(
|
||||
PaginationState(
|
||||
items: [],
|
||||
isLoading: true,
|
||||
isReloading: true,
|
||||
totalCount: null,
|
||||
hasMore: true,
|
||||
cursor: null,
|
||||
),
|
||||
);
|
||||
|
||||
final newState = await AsyncValue.guard<List<T>>(() async {
|
||||
return await fetch();
|
||||
});
|
||||
state = newState;
|
||||
isLoading = false;
|
||||
final newItems = await fetch();
|
||||
|
||||
if (!ref.mounted) return;
|
||||
state = AsyncData(
|
||||
PaginationState(
|
||||
items: newItems,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> fetchFurther() async {
|
||||
if (fetchedAll) return;
|
||||
if (isLoading) return;
|
||||
|
||||
isLoading = true;
|
||||
state = AsyncLoading<List<T>>();
|
||||
state = AsyncData(state.value!.copyWith(isLoading: true));
|
||||
|
||||
final newState = await AsyncValue.guard<List<T>>(() async {
|
||||
final elements = await fetch();
|
||||
return [...?state.value, ...elements];
|
||||
});
|
||||
final newItems = await fetch();
|
||||
|
||||
state = newState;
|
||||
isLoading = false;
|
||||
if (!ref.mounted) return;
|
||||
state = AsyncData(
|
||||
state.value!.copyWith(
|
||||
items: [...state.value!.items, ...newItems],
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,16 +169,31 @@ mixin AsyncPaginationFilter<F, T> on AsyncPaginationController<T>
|
||||
@override
|
||||
Future<void> applyFilter(F filter) async {
|
||||
if (currentFilter == filter) return;
|
||||
// Reset the data
|
||||
isLoading = true;
|
||||
totalCount = null;
|
||||
state = AsyncData<List<T>>([]);
|
||||
|
||||
state = AsyncData(
|
||||
PaginationState(
|
||||
items: [],
|
||||
isLoading: true,
|
||||
isReloading: true,
|
||||
totalCount: null,
|
||||
hasMore: true,
|
||||
cursor: null,
|
||||
),
|
||||
);
|
||||
currentFilter = filter;
|
||||
|
||||
final newState = await AsyncValue.guard<List<T>>(() async {
|
||||
return await fetch();
|
||||
});
|
||||
state = newState;
|
||||
isLoading = false;
|
||||
final newItems = await fetch();
|
||||
|
||||
if (!ref.mounted) return;
|
||||
state = AsyncData(
|
||||
PaginationState(
|
||||
items: newItems,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// Post Categories Notifier
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/post_category.dart';
|
||||
import 'package:island/models/post_tag.dart';
|
||||
@@ -8,11 +10,25 @@ import 'package:island/pods/paging.dart';
|
||||
final postCategoriesProvider =
|
||||
AsyncNotifierProvider.autoDispose<
|
||||
PostCategoriesNotifier,
|
||||
List<SnPostCategory>
|
||||
PaginationState<SnPostCategory>
|
||||
>(PostCategoriesNotifier.new);
|
||||
|
||||
class PostCategoriesNotifier extends AsyncNotifier<List<SnPostCategory>>
|
||||
class PostCategoriesNotifier
|
||||
extends AsyncNotifier<PaginationState<SnPostCategory>>
|
||||
with AsyncPaginationController<SnPostCategory> {
|
||||
@override
|
||||
FutureOr<PaginationState<SnPostCategory>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SnPostCategory>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
@@ -30,12 +46,26 @@ class PostCategoriesNotifier extends AsyncNotifier<List<SnPostCategory>>
|
||||
|
||||
// Post Tags Notifier
|
||||
final postTagsProvider =
|
||||
AsyncNotifierProvider.autoDispose<PostTagsNotifier, List<SnPostTag>>(
|
||||
PostTagsNotifier.new,
|
||||
);
|
||||
AsyncNotifierProvider.autoDispose<
|
||||
PostTagsNotifier,
|
||||
PaginationState<SnPostTag>
|
||||
>(PostTagsNotifier.new);
|
||||
|
||||
class PostTagsNotifier extends AsyncNotifier<List<SnPostTag>>
|
||||
class PostTagsNotifier extends AsyncNotifier<PaginationState<SnPostTag>>
|
||||
with AsyncPaginationController<SnPostTag> {
|
||||
@override
|
||||
FutureOr<PaginationState<SnPostTag>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SnPostTag>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
@@ -39,7 +41,7 @@ final postListProvider = AsyncNotifierProvider.autoDispose.family(
|
||||
PostListNotifier.new,
|
||||
);
|
||||
|
||||
class PostListNotifier extends AsyncNotifier<List<SnPost>>
|
||||
class PostListNotifier extends AsyncNotifier<PaginationState<SnPost>>
|
||||
with
|
||||
AsyncPaginationController<SnPost>,
|
||||
AsyncPaginationFilter<PostListQuery, SnPost> {
|
||||
@@ -53,9 +55,17 @@ class PostListNotifier extends AsyncNotifier<List<SnPost>>
|
||||
late PostListQuery currentFilter;
|
||||
|
||||
@override
|
||||
Future<List<SnPost>> build() async {
|
||||
FutureOr<PaginationState<SnPost>> build() async {
|
||||
currentFilter = config.initialFilter;
|
||||
return fetch();
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'site_files.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(siteFiles)
|
||||
const siteFilesProvider = SiteFilesFamily._();
|
||||
final siteFilesProvider = SiteFilesFamily._();
|
||||
|
||||
final class SiteFilesProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class SiteFilesProvider
|
||||
with
|
||||
$FutureModifier<List<SnSiteFileEntry>>,
|
||||
$FutureProvider<List<SnSiteFileEntry>> {
|
||||
const SiteFilesProvider._({
|
||||
SiteFilesProvider._({
|
||||
required SiteFilesFamily super.from,
|
||||
required ({String siteId, String? path}) super.argument,
|
||||
}) : super(
|
||||
@@ -74,7 +74,7 @@ final class SiteFilesFamily extends $Family
|
||||
FutureOr<List<SnSiteFileEntry>>,
|
||||
({String siteId, String? path})
|
||||
> {
|
||||
const SiteFilesFamily._()
|
||||
SiteFilesFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'siteFilesProvider',
|
||||
@@ -91,7 +91,7 @@ final class SiteFilesFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(siteFileContent)
|
||||
const siteFileContentProvider = SiteFileContentFamily._();
|
||||
final siteFileContentProvider = SiteFileContentFamily._();
|
||||
|
||||
final class SiteFileContentProvider
|
||||
extends
|
||||
@@ -101,7 +101,7 @@ final class SiteFileContentProvider
|
||||
FutureOr<SnFileContent>
|
||||
>
|
||||
with $FutureModifier<SnFileContent>, $FutureProvider<SnFileContent> {
|
||||
const SiteFileContentProvider._({
|
||||
SiteFileContentProvider._({
|
||||
required SiteFileContentFamily super.from,
|
||||
required ({String siteId, String relativePath}) super.argument,
|
||||
}) : super(
|
||||
@@ -157,7 +157,7 @@ final class SiteFileContentFamily extends $Family
|
||||
FutureOr<SnFileContent>,
|
||||
({String siteId, String relativePath})
|
||||
> {
|
||||
const SiteFileContentFamily._()
|
||||
SiteFileContentFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'siteFileContentProvider',
|
||||
@@ -179,12 +179,12 @@ final class SiteFileContentFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(siteFileContentRaw)
|
||||
const siteFileContentRawProvider = SiteFileContentRawFamily._();
|
||||
final siteFileContentRawProvider = SiteFileContentRawFamily._();
|
||||
|
||||
final class SiteFileContentRawProvider
|
||||
extends $FunctionalProvider<AsyncValue<String>, String, FutureOr<String>>
|
||||
with $FutureModifier<String>, $FutureProvider<String> {
|
||||
const SiteFileContentRawProvider._({
|
||||
SiteFileContentRawProvider._({
|
||||
required SiteFileContentRawFamily super.from,
|
||||
required ({String siteId, String relativePath}) super.argument,
|
||||
}) : super(
|
||||
@@ -240,7 +240,7 @@ final class SiteFileContentRawFamily extends $Family
|
||||
FutureOr<String>,
|
||||
({String siteId, String relativePath})
|
||||
> {
|
||||
const SiteFileContentRawFamily._()
|
||||
SiteFileContentRawFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'siteFileContentRawProvider',
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'site_pages.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(sitePages)
|
||||
const sitePagesProvider = SitePagesFamily._();
|
||||
final sitePagesProvider = SitePagesFamily._();
|
||||
|
||||
final class SitePagesProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class SitePagesProvider
|
||||
with
|
||||
$FutureModifier<List<SnPublicationPage>>,
|
||||
$FutureProvider<List<SnPublicationPage>> {
|
||||
const SitePagesProvider._({
|
||||
SitePagesProvider._({
|
||||
required SitePagesFamily super.from,
|
||||
required (String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -74,7 +74,7 @@ final class SitePagesFamily extends $Family
|
||||
FutureOr<List<SnPublicationPage>>,
|
||||
(String, String)
|
||||
> {
|
||||
const SitePagesFamily._()
|
||||
SitePagesFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'sitePagesProvider',
|
||||
@@ -91,7 +91,7 @@ final class SitePagesFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(sitePage)
|
||||
const sitePageProvider = SitePageFamily._();
|
||||
final sitePageProvider = SitePageFamily._();
|
||||
|
||||
final class SitePageProvider
|
||||
extends
|
||||
@@ -103,7 +103,7 @@ final class SitePageProvider
|
||||
with
|
||||
$FutureModifier<SnPublicationPage>,
|
||||
$FutureProvider<SnPublicationPage> {
|
||||
const SitePageProvider._({
|
||||
SitePageProvider._({
|
||||
required SitePageFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -151,7 +151,7 @@ String _$sitePageHash() => r'542f70c5b103fe34d7cf7eb0821d52f017022efc';
|
||||
|
||||
final class SitePageFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnPublicationPage>, String> {
|
||||
const SitePageFamily._()
|
||||
SitePageFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'sitePageProvider',
|
||||
|
||||
@@ -10,12 +10,12 @@ part of 'theme.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(theme)
|
||||
const themeProvider = ThemeProvider._();
|
||||
final themeProvider = ThemeProvider._();
|
||||
|
||||
final class ThemeProvider
|
||||
extends $FunctionalProvider<ThemeSet, ThemeSet, ThemeSet>
|
||||
with $Provider<ThemeSet> {
|
||||
const ThemeProvider._()
|
||||
ThemeProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/activity.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
|
||||
@@ -7,25 +10,39 @@ final activityListProvider = AsyncNotifierProvider.autoDispose(
|
||||
ActivityListNotifier.new,
|
||||
);
|
||||
|
||||
class ActivityListNotifier extends AsyncNotifier<List<SnTimelineEvent>>
|
||||
class ActivityListNotifier
|
||||
extends AsyncNotifier<PaginationState<SnTimelineEvent>>
|
||||
with
|
||||
AsyncPaginationController<SnTimelineEvent>,
|
||||
AsyncPaginationFilter<String?, SnTimelineEvent> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
FutureOr<PaginationState<SnTimelineEvent>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String? currentFilter;
|
||||
|
||||
@override
|
||||
Future<List<SnTimelineEvent>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
|
||||
final cursor = state.value?.lastOrNull?.createdAt.toUtc().toIso8601String();
|
||||
final settings = ref.read(appSettingsProvider);
|
||||
|
||||
final queryParameters = {
|
||||
if (cursor != null) 'cursor': cursor,
|
||||
'take': pageSize,
|
||||
if (currentFilter != null) 'filter': currentFilter,
|
||||
'showFediverse': settings.showFediverseContent,
|
||||
};
|
||||
|
||||
final response = await client.get(
|
||||
@@ -37,10 +54,16 @@ class ActivityListNotifier extends AsyncNotifier<List<SnTimelineEvent>>
|
||||
.map((e) => SnTimelineEvent.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
|
||||
final hasMore = (items.firstOrNull?.type ?? 'empty') != 'empty';
|
||||
|
||||
totalCount =
|
||||
(state.value?.length ?? 0) + items.length + (hasMore ? pageSize : 0);
|
||||
hasMore = (items.firstOrNull?.type ?? 'empty') != 'empty';
|
||||
// Find the latest createdAt timestamp from all items for cursor-based pagination
|
||||
// This ensures we get items created before this timestamp, regardless of sort order
|
||||
if (items.isNotEmpty) {
|
||||
final latestCreatedAt = items
|
||||
.where((e) => e.type.startsWith('posts.'))
|
||||
.map((e) => e.createdAt)
|
||||
.reduce((a, b) => a.isBefore(b) ? a : b);
|
||||
cursor = latestCreatedAt.toUtc().toIso8601String();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
@@ -49,9 +72,9 @@ class ActivityListNotifier extends AsyncNotifier<List<SnTimelineEvent>>
|
||||
final currentState = state.value;
|
||||
if (currentState == null) return;
|
||||
|
||||
final updatedItems = [...currentState];
|
||||
final updatedItems = [...currentState.items];
|
||||
updatedItems[index] = activity;
|
||||
|
||||
state = AsyncData(updatedItems);
|
||||
state = AsyncData(currentState.copyWith(items: updatedItems));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ part of 'translate.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(translateString)
|
||||
const translateStringProvider = TranslateStringFamily._();
|
||||
final translateStringProvider = TranslateStringFamily._();
|
||||
|
||||
final class TranslateStringProvider
|
||||
extends $FunctionalProvider<AsyncValue<String>, String, FutureOr<String>>
|
||||
with $FutureModifier<String>, $FutureProvider<String> {
|
||||
const TranslateStringProvider._({
|
||||
TranslateStringProvider._({
|
||||
required TranslateStringFamily super.from,
|
||||
required TranslateQuery super.argument,
|
||||
}) : super(
|
||||
@@ -62,7 +62,7 @@ String _$translateStringHash() => r'51d638cf07cbf3ffa9469298f5bd9c667bc0ccb7';
|
||||
|
||||
final class TranslateStringFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<String>, TranslateQuery> {
|
||||
const TranslateStringFamily._()
|
||||
TranslateStringFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'translateStringProvider',
|
||||
@@ -79,12 +79,12 @@ final class TranslateStringFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(detectStringLanguage)
|
||||
const detectStringLanguageProvider = DetectStringLanguageFamily._();
|
||||
final detectStringLanguageProvider = DetectStringLanguageFamily._();
|
||||
|
||||
final class DetectStringLanguageProvider
|
||||
extends $FunctionalProvider<String?, String?, String?>
|
||||
with $Provider<String?> {
|
||||
const DetectStringLanguageProvider._({
|
||||
DetectStringLanguageProvider._({
|
||||
required DetectStringLanguageFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -140,7 +140,7 @@ String _$detectStringLanguageHash() =>
|
||||
|
||||
final class DetectStringLanguageFamily extends $Family
|
||||
with $FunctionalFamilyOverride<String?, String> {
|
||||
const DetectStringLanguageFamily._()
|
||||
DetectStringLanguageFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'detectStringLanguageProvider',
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'package:island/pods/network.dart';
|
||||
final webFeedListProvider = FutureProvider.autoDispose
|
||||
.family<List<SnWebFeed>, String>((ref, pubName) async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final response = await client.get('/sphere/publishers/$pubName/feeds');
|
||||
final response = await client.get('/insight/publishers/$pubName/feeds');
|
||||
return (response.data as List)
|
||||
.map((json) => SnWebFeed.fromJson(json))
|
||||
.toList();
|
||||
|
||||
104
lib/route.dart
104
lib/route.dart
@@ -18,7 +18,7 @@ import 'package:island/screens/files/file_list.dart';
|
||||
import 'package:island/screens/files/file_detail.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_search.dart';
|
||||
import 'package:island/screens/search.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/app_wrapper.dart';
|
||||
import 'package:island/screens/tabs.dart';
|
||||
@@ -169,6 +169,7 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
builder: (context, state) => const AboutScreen(),
|
||||
),
|
||||
|
||||
// File routes
|
||||
GoRoute(
|
||||
name: 'fileDetail',
|
||||
path: '/files/:id',
|
||||
@@ -185,6 +186,56 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
},
|
||||
),
|
||||
|
||||
// Post routes
|
||||
GoRoute(
|
||||
name: 'postShuffle',
|
||||
path: '/posts/shuffle',
|
||||
builder: (context, state) => const PostShuffleScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postCategories',
|
||||
path: '/posts/categories',
|
||||
builder: (context, state) => const PostCategoriesListScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postCategoryDetail',
|
||||
path: '/posts/categories/:slug',
|
||||
builder: (context, state) {
|
||||
final slug = state.pathParameters['slug']!;
|
||||
return PostCategoryDetailScreen(slug: slug, isCategory: true);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postTagDetail',
|
||||
path: '/posts/tags/:slug',
|
||||
builder: (context, state) {
|
||||
final slug = state.pathParameters['slug']!;
|
||||
return PostCategoryDetailScreen(slug: slug, isCategory: false);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postDetail',
|
||||
path: '/posts/:id',
|
||||
builder: (context, state) {
|
||||
final id = state.pathParameters['id']!;
|
||||
return PostDetailScreen(id: id);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'publisherProfile',
|
||||
path: '/publishers/:name',
|
||||
builder: (context, state) {
|
||||
final name = state.pathParameters['name']!;
|
||||
return PublisherProfileScreen(name: name);
|
||||
},
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
name: 'universalSearch',
|
||||
path: '/search',
|
||||
builder: (context, state) => const UniversalSearchScreen(),
|
||||
),
|
||||
|
||||
// Main tabs with TabsScreen shell
|
||||
ShellRoute(
|
||||
navigatorKey: _tabsShellKey,
|
||||
@@ -212,56 +263,7 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
transitionsBuilder: _tabPagesTransitionBuilder,
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postSearch',
|
||||
path: '/posts/search',
|
||||
builder: (context, state) => const PostSearchScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postShuffle',
|
||||
path: '/posts/shuffle',
|
||||
builder: (context, state) => const PostShuffleScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postCategories',
|
||||
path: '/posts/categories',
|
||||
builder: (context, state) => const PostCategoriesListScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postCategoryDetail',
|
||||
path: '/posts/categories/:slug',
|
||||
builder: (context, state) {
|
||||
final slug = state.pathParameters['slug']!;
|
||||
return PostCategoryDetailScreen(slug: slug, isCategory: true);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postTagDetail',
|
||||
path: '/posts/tags/:slug',
|
||||
builder: (context, state) {
|
||||
final slug = state.pathParameters['slug']!;
|
||||
return PostCategoryDetailScreen(
|
||||
slug: slug,
|
||||
isCategory: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postDetail',
|
||||
path: '/posts/:id',
|
||||
builder: (context, state) {
|
||||
final id = state.pathParameters['id']!;
|
||||
return PostDetailScreen(id: id);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
name: 'publisherProfile',
|
||||
path: '/publishers/:name',
|
||||
builder: (context, state) {
|
||||
final name = state.pathParameters['name']!;
|
||||
return PublisherProfileScreen(name: name);
|
||||
},
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
name: 'discoveryRealms',
|
||||
path: '/discovery/realms',
|
||||
|
||||
@@ -74,7 +74,7 @@ class AccountScreen extends HookConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (user.value?.profile.background?.id != null)
|
||||
if (user.value?.profile.background != null)
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
@@ -112,7 +112,7 @@ class AccountScreen extends HookConsumerWidget {
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final hasBackground =
|
||||
user.value?.profile.background?.id != null;
|
||||
user.value?.profile.background != null;
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: hasBackground ? 0 : 16,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
@@ -28,10 +30,23 @@ final socialCreditHistoryNotifierProvider = AsyncNotifierProvider.autoDispose(
|
||||
);
|
||||
|
||||
class SocialCreditHistoryNotifier
|
||||
extends AsyncNotifier<List<SnSocialCreditRecord>>
|
||||
extends AsyncNotifier<PaginationState<SnSocialCreditRecord>>
|
||||
with AsyncPaginationController<SnSocialCreditRecord> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
FutureOr<PaginationState<SnSocialCreditRecord>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SnSocialCreditRecord>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
|
||||
@@ -10,12 +10,12 @@ part of 'credits.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(socialCredits)
|
||||
const socialCreditsProvider = SocialCreditsProvider._();
|
||||
final socialCreditsProvider = SocialCreditsProvider._();
|
||||
|
||||
final class SocialCreditsProvider
|
||||
extends $FunctionalProvider<AsyncValue<double>, double, FutureOr<double>>
|
||||
with $FutureModifier<double>, $FutureProvider<double> {
|
||||
const SocialCreditsProvider._()
|
||||
SocialCreditsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -14,14 +16,30 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
final levelingHistoryNotifierProvider = AsyncNotifierProvider.autoDispose(
|
||||
LevelingHistoryNotifier.new,
|
||||
);
|
||||
final levelingHistoryNotifierProvider =
|
||||
AsyncNotifierProvider.autoDispose<
|
||||
LevelingHistoryNotifier,
|
||||
PaginationState<SnExperienceRecord>
|
||||
>(LevelingHistoryNotifier.new);
|
||||
|
||||
class LevelingHistoryNotifier extends AsyncNotifier<List<SnExperienceRecord>>
|
||||
class LevelingHistoryNotifier
|
||||
extends AsyncNotifier<PaginationState<SnExperienceRecord>>
|
||||
with AsyncPaginationController<SnExperienceRecord> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
FutureOr<PaginationState<SnExperienceRecord>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SnExperienceRecord>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'account_settings.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(authFactors)
|
||||
const authFactorsProvider = AuthFactorsProvider._();
|
||||
final authFactorsProvider = AuthFactorsProvider._();
|
||||
|
||||
final class AuthFactorsProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class AuthFactorsProvider
|
||||
with
|
||||
$FutureModifier<List<SnAuthFactor>>,
|
||||
$FutureProvider<List<SnAuthFactor>> {
|
||||
const AuthFactorsProvider._()
|
||||
AuthFactorsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -51,7 +51,7 @@ final class AuthFactorsProvider
|
||||
String _$authFactorsHash() => r'ed87d7dbd421fef0a5620416727c3dc598c97ef5';
|
||||
|
||||
@ProviderFor(contactMethods)
|
||||
const contactMethodsProvider = ContactMethodsProvider._();
|
||||
final contactMethodsProvider = ContactMethodsProvider._();
|
||||
|
||||
final class ContactMethodsProvider
|
||||
extends
|
||||
@@ -63,7 +63,7 @@ final class ContactMethodsProvider
|
||||
with
|
||||
$FutureModifier<List<SnContactMethod>>,
|
||||
$FutureProvider<List<SnContactMethod>> {
|
||||
const ContactMethodsProvider._()
|
||||
ContactMethodsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -92,7 +92,7 @@ final class ContactMethodsProvider
|
||||
String _$contactMethodsHash() => r'1d3d03e9ffbf36126236558ead22cb7d88bb9cb2';
|
||||
|
||||
@ProviderFor(accountConnections)
|
||||
const accountConnectionsProvider = AccountConnectionsProvider._();
|
||||
final accountConnectionsProvider = AccountConnectionsProvider._();
|
||||
|
||||
final class AccountConnectionsProvider
|
||||
extends
|
||||
@@ -104,7 +104,7 @@ final class AccountConnectionsProvider
|
||||
with
|
||||
$FutureModifier<List<SnAccountConnection>>,
|
||||
$FutureProvider<List<SnAccountConnection>> {
|
||||
const AccountConnectionsProvider._()
|
||||
AccountConnectionsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
|
||||
@@ -74,14 +74,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
final cloudFile =
|
||||
await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
).future;
|
||||
final cloudFile = await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(data: result, type: UniversalFileType.image),
|
||||
).future;
|
||||
if (cloudFile == null) {
|
||||
throw ArgumentError('Failed to upload the file...');
|
||||
}
|
||||
@@ -188,8 +184,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
if (usernameColorType.value == 'gradient') ...{
|
||||
if (usernameColorDirection.text.isNotEmpty)
|
||||
'direction': usernameColorDirection.text,
|
||||
'colors':
|
||||
usernameColorColors.value.where((c) => c.isNotEmpty).toList(),
|
||||
'colors': usernameColorColors.value
|
||||
.where((c) => c.isNotEmpty)
|
||||
.toList(),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -206,18 +203,16 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
'time_zone': timeZoneController.text,
|
||||
'birthday': birthday.value?.toUtc().toIso8601String(),
|
||||
'username_color': usernameColorData,
|
||||
'links':
|
||||
links.value
|
||||
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
|
||||
.toList(),
|
||||
'links': links.value
|
||||
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
|
||||
.toList(),
|
||||
},
|
||||
);
|
||||
final userNotifier = ref.read(userInfoProvider.notifier);
|
||||
userNotifier.fetchUser();
|
||||
links.value =
|
||||
links.value
|
||||
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
|
||||
.toList();
|
||||
links.value = links.value
|
||||
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
|
||||
.toList();
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
@@ -244,13 +239,12 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
child:
|
||||
user.value!.profile.background?.id != null
|
||||
? CloudImageWidget(
|
||||
fileId: user.value!.profile.background!.id,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
child: user.value!.profile.background != null
|
||||
? CloudImageWidget(
|
||||
file: user.value!.profile.background,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
onTap: () {
|
||||
updateProfilePicture('background');
|
||||
@@ -261,7 +255,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
bottom: -32,
|
||||
child: GestureDetector(
|
||||
child: ProfilePictureWidget(
|
||||
fileId: user.value!.profile.picture?.id,
|
||||
file: user.value!.profile.picture,
|
||||
radius: 40,
|
||||
),
|
||||
onTap: () {
|
||||
@@ -291,14 +285,14 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
),
|
||||
controller: usernameController,
|
||||
readOnly: true,
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: 'nickname'.tr()),
|
||||
controller: nicknameController,
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
DropdownButtonFormField2<String>(
|
||||
decoration: InputDecoration(
|
||||
@@ -385,9 +379,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
labelText: 'firstName'.tr(),
|
||||
),
|
||||
controller: firstNameController,
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -396,9 +389,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
labelText: 'middleName'.tr(),
|
||||
),
|
||||
controller: middleNameController,
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -407,9 +399,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
labelText: 'lastName'.tr(),
|
||||
),
|
||||
controller: lastNameController,
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -423,8 +414,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
maxLines: null,
|
||||
minLines: 3,
|
||||
controller: bioController,
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
Row(
|
||||
spacing: 16,
|
||||
@@ -445,33 +436,34 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
onSelected: (String selection) {
|
||||
genderController.text = selection;
|
||||
},
|
||||
fieldViewBuilder: (
|
||||
context,
|
||||
controller,
|
||||
focusNode,
|
||||
onFieldSubmitted,
|
||||
) {
|
||||
// Initialize the controller with the current value
|
||||
if (controller.text.isEmpty &&
|
||||
genderController.text.isNotEmpty) {
|
||||
controller.text = genderController.text;
|
||||
}
|
||||
fieldViewBuilder:
|
||||
(
|
||||
context,
|
||||
controller,
|
||||
focusNode,
|
||||
onFieldSubmitted,
|
||||
) {
|
||||
// Initialize the controller with the current value
|
||||
if (controller.text.isEmpty &&
|
||||
genderController.text.isNotEmpty) {
|
||||
controller.text = genderController.text;
|
||||
}
|
||||
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'gender'.tr(),
|
||||
),
|
||||
onChanged: (value) {
|
||||
genderController.text = value;
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'gender'.tr(),
|
||||
),
|
||||
onChanged: (value) {
|
||||
genderController.text = value;
|
||||
},
|
||||
onTapOutside: (_) => FocusManager
|
||||
.instance
|
||||
.primaryFocus
|
||||
?.unfocus(),
|
||||
);
|
||||
},
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus
|
||||
?.unfocus(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -480,9 +472,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
labelText: 'pronouns'.tr(),
|
||||
),
|
||||
controller: pronounsController,
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -496,9 +487,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
labelText: 'location'.tr(),
|
||||
),
|
||||
controller: locationController,
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -507,8 +497,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
if (textEditingValue.text.isEmpty) {
|
||||
return const Iterable<String>.empty();
|
||||
}
|
||||
final lowercaseQuery =
|
||||
textEditingValue.text.toLowerCase();
|
||||
final lowercaseQuery = textEditingValue.text
|
||||
.toLowerCase();
|
||||
return getAvailableTz().where((tz) {
|
||||
return tz.toLowerCase().contains(lowercaseQuery);
|
||||
});
|
||||
@@ -516,46 +506,49 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
onSelected: (String selection) {
|
||||
timeZoneController.text = selection;
|
||||
},
|
||||
fieldViewBuilder: (
|
||||
context,
|
||||
controller,
|
||||
focusNode,
|
||||
onFieldSubmitted,
|
||||
) {
|
||||
// Sync the controller with timeZoneController when the widget is built
|
||||
if (controller.text != timeZoneController.text) {
|
||||
controller.text = timeZoneController.text;
|
||||
}
|
||||
fieldViewBuilder:
|
||||
(
|
||||
context,
|
||||
controller,
|
||||
focusNode,
|
||||
onFieldSubmitted,
|
||||
) {
|
||||
// Sync the controller with timeZoneController when the widget is built
|
||||
if (controller.text !=
|
||||
timeZoneController.text) {
|
||||
controller.text = timeZoneController.text;
|
||||
}
|
||||
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'timeZone'.tr(),
|
||||
suffix: InkWell(
|
||||
child: const Icon(
|
||||
Symbols.my_location,
|
||||
size: 18,
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'timeZone'.tr(),
|
||||
suffix: InkWell(
|
||||
child: const Icon(
|
||||
Symbols.my_location,
|
||||
size: 18,
|
||||
),
|
||||
onTap: () async {
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
final machineTz =
|
||||
await getMachineTz();
|
||||
controller.text = machineTz;
|
||||
timeZoneController.text = machineTz;
|
||||
} finally {
|
||||
if (context.mounted) {
|
||||
hideLoadingModal(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
final machineTz = await getMachineTz();
|
||||
controller.text = machineTz;
|
||||
timeZoneController.text = machineTz;
|
||||
} finally {
|
||||
if (context.mounted) {
|
||||
hideLoadingModal(context);
|
||||
}
|
||||
}
|
||||
onChanged: (value) {
|
||||
timeZoneController.text = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
onChanged: (value) {
|
||||
timeZoneController.text = value;
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
optionsViewBuilder: (context, onSelected, options) {
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
@@ -569,21 +562,21 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
itemCount: options.length,
|
||||
itemBuilder: (
|
||||
BuildContext context,
|
||||
int index,
|
||||
) {
|
||||
final option = options.elementAt(index);
|
||||
return ListTile(
|
||||
title: Text(
|
||||
option,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
onTap: () {
|
||||
onSelected(option);
|
||||
itemBuilder:
|
||||
(BuildContext context, int index) {
|
||||
final option = options.elementAt(
|
||||
index,
|
||||
);
|
||||
return ListTile(
|
||||
title: Text(
|
||||
option,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
onTap: () {
|
||||
onSelected(option);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -644,10 +637,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainerHighest,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Column(
|
||||
@@ -664,25 +656,23 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
type: usernameColorType.value,
|
||||
value:
|
||||
usernameColorType.value == 'plain' &&
|
||||
usernameColorValue
|
||||
.text
|
||||
.isNotEmpty
|
||||
? usernameColorValue.text
|
||||
: null,
|
||||
usernameColorValue.text.isNotEmpty
|
||||
? usernameColorValue.text
|
||||
: null,
|
||||
direction:
|
||||
usernameColorType.value ==
|
||||
'gradient' &&
|
||||
usernameColorDirection
|
||||
.text
|
||||
.isNotEmpty
|
||||
? usernameColorDirection.text
|
||||
: null,
|
||||
'gradient' &&
|
||||
usernameColorDirection
|
||||
.text
|
||||
.isNotEmpty
|
||||
? usernameColorDirection.text
|
||||
: null,
|
||||
colors:
|
||||
usernameColorType.value == 'gradient'
|
||||
? usernameColorColors.value
|
||||
.where((c) => c.isNotEmpty)
|
||||
.toList()
|
||||
: null,
|
||||
? usernameColorColors.value
|
||||
.where((c) => c.isNotEmpty)
|
||||
.toList()
|
||||
: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -724,10 +714,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
? Symbols.check_circle
|
||||
: Symbols.error,
|
||||
size: 16,
|
||||
color:
|
||||
canUseColor
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
color: canUseColor
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
const Gap(4),
|
||||
Text(
|
||||
@@ -736,10 +725,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
: 'upgradeRequired'.tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
canUseColor
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
color: canUseColor
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -792,34 +780,35 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
onSelected: (String selection) {
|
||||
usernameColorValue.text = selection;
|
||||
},
|
||||
fieldViewBuilder: (
|
||||
context,
|
||||
controller,
|
||||
focusNode,
|
||||
onFieldSubmitted,
|
||||
) {
|
||||
// Initialize the controller with the current value
|
||||
if (controller.text.isEmpty &&
|
||||
usernameColorValue.text.isNotEmpty) {
|
||||
controller.text = usernameColorValue.text;
|
||||
}
|
||||
fieldViewBuilder:
|
||||
(
|
||||
context,
|
||||
controller,
|
||||
focusNode,
|
||||
onFieldSubmitted,
|
||||
) {
|
||||
// Initialize the controller with the current value
|
||||
if (controller.text.isEmpty &&
|
||||
usernameColorValue.text.isNotEmpty) {
|
||||
controller.text = usernameColorValue.text;
|
||||
}
|
||||
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'colorValue'.tr(),
|
||||
hintText: 'e.g. red or #ff6600',
|
||||
),
|
||||
onChanged: (value) {
|
||||
usernameColorValue.text = value;
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'colorValue'.tr(),
|
||||
hintText: 'e.g. red or #ff6600',
|
||||
),
|
||||
onChanged: (value) {
|
||||
usernameColorValue.text = value;
|
||||
},
|
||||
onTapOutside: (_) => FocusManager
|
||||
.instance
|
||||
.primaryFocus
|
||||
?.unfocus(),
|
||||
);
|
||||
},
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus
|
||||
?.unfocus(),
|
||||
);
|
||||
},
|
||||
),
|
||||
if (usernameColorType.value == 'gradient') ...[
|
||||
DropdownButtonFormField2<String>(
|
||||
@@ -862,10 +851,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
child: Text('gradientDirectionToTopLeft'.tr()),
|
||||
),
|
||||
],
|
||||
value:
|
||||
usernameColorDirection.text.isNotEmpty
|
||||
? usernameColorDirection.text
|
||||
: 'to right',
|
||||
value: usernameColorDirection.text.isNotEmpty
|
||||
? usernameColorDirection.text
|
||||
: 'to right',
|
||||
onChanged: (value) {
|
||||
usernameColorDirection.text = value ?? 'to right';
|
||||
},
|
||||
@@ -911,21 +899,19 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
onChanged: (value) {
|
||||
usernameColorColors.value[i] = value;
|
||||
},
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus
|
||||
?.unfocus(),
|
||||
onTapOutside: (_) => FocusManager
|
||||
.instance
|
||||
.primaryFocus
|
||||
?.unfocus(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Symbols.delete),
|
||||
onPressed: () {
|
||||
usernameColorColors.value =
|
||||
usernameColorColors.value
|
||||
.whereIndexed(
|
||||
(idx, _) => idx != i,
|
||||
)
|
||||
.toList();
|
||||
usernameColorColors
|
||||
.value = usernameColorColors.value
|
||||
.whereIndexed((idx, _) => idx != i)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -968,10 +954,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
name: value,
|
||||
);
|
||||
},
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus
|
||||
?.unfocus(),
|
||||
onTapOutside: (_) => FocusManager
|
||||
.instance
|
||||
.primaryFocus
|
||||
?.unfocus(),
|
||||
),
|
||||
),
|
||||
const Gap(8),
|
||||
@@ -987,19 +973,18 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
url: value,
|
||||
);
|
||||
},
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus
|
||||
?.unfocus(),
|
||||
onTapOutside: (_) => FocusManager
|
||||
.instance
|
||||
.primaryFocus
|
||||
?.unfocus(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Symbols.delete),
|
||||
onPressed: () {
|
||||
links.value =
|
||||
links.value
|
||||
.whereIndexed((idx, _) => idx != i)
|
||||
.toList();
|
||||
links.value = links.value
|
||||
.whereIndexed((idx, _) => idx != i)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -57,7 +57,7 @@ class _AccountBasicInfo extends StatelessWidget {
|
||||
return Card(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final hasBackground = data.profile.background?.id != null;
|
||||
final hasBackground = data.profile.background != null;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -476,9 +476,9 @@ class _AccountPublisherList extends StatelessWidget {
|
||||
subtitle: Text(
|
||||
publisher.bio.isNotEmpty
|
||||
? publisher.bio
|
||||
.split('\n')
|
||||
.where((line) => line.trim().isNotEmpty)
|
||||
.join('\n')
|
||||
.split('\n')
|
||||
.where((line) => line.trim().isNotEmpty)
|
||||
.join('\n')
|
||||
: 'descriptionNone'.tr(),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -550,16 +550,14 @@ class _AccountAction extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: relationshipAction,
|
||||
label:
|
||||
Text(
|
||||
accountRelationship.value == null
|
||||
? 'addFriendShort'
|
||||
: 'added',
|
||||
).tr(),
|
||||
icon:
|
||||
accountRelationship.value == null
|
||||
? const Icon(Symbols.person_add)
|
||||
: const Icon(Symbols.person_check),
|
||||
label: Text(
|
||||
accountRelationship.value == null
|
||||
? 'addFriendShort'
|
||||
: 'added',
|
||||
).tr(),
|
||||
icon: accountRelationship.value == null
|
||||
? const Icon(Symbols.person_add)
|
||||
: const Icon(Symbols.person_check),
|
||||
),
|
||||
),
|
||||
if (accountRelationship.value == null ||
|
||||
@@ -579,16 +577,14 @@ class _AccountAction extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: blockAction,
|
||||
label:
|
||||
Text(
|
||||
accountRelationship.value == null
|
||||
? 'blockUser'
|
||||
: 'unblockUser',
|
||||
).tr(),
|
||||
icon:
|
||||
accountRelationship.value == null
|
||||
? const Icon(Symbols.block)
|
||||
: const Icon(Symbols.person_cancel),
|
||||
label: Text(
|
||||
accountRelationship.value == null
|
||||
? 'blockUser'
|
||||
: 'unblockUser',
|
||||
).tr(),
|
||||
icon: accountRelationship.value == null
|
||||
? const Icon(Symbols.block)
|
||||
: const Icon(Symbols.person_cancel),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -600,13 +596,12 @@ class _AccountAction extends StatelessWidget {
|
||||
child: FilledButton.icon(
|
||||
onPressed: directMessageAction,
|
||||
icon: const Icon(Symbols.message),
|
||||
label:
|
||||
Text(
|
||||
accountChat.value == null
|
||||
? 'createDirectMessage'
|
||||
: 'gotoDirectMessage',
|
||||
maxLines: 1,
|
||||
).tr(),
|
||||
label: Text(
|
||||
accountChat.value == null
|
||||
? 'createDirectMessage'
|
||||
: 'gotoDirectMessage',
|
||||
maxLines: 1,
|
||||
).tr(),
|
||||
),
|
||||
),
|
||||
IconButton.filled(
|
||||
@@ -664,7 +659,7 @@ Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async {
|
||||
if (account.profile.background == null) return null;
|
||||
final colors = await ColorExtractionService.getColorsFromImage(
|
||||
CloudImageWidget.provider(
|
||||
fileId: account.profile.background!.id,
|
||||
file: account.profile.background!,
|
||||
serverUrl: ref.watch(serverUrlProvider),
|
||||
),
|
||||
);
|
||||
@@ -683,7 +678,7 @@ Future<SnChatRoom?> accountDirectChat(Ref ref, String uname) async {
|
||||
final account = await ref.watch(accountProvider(uname).future);
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
try {
|
||||
final resp = await apiClient.get("/sphere/chat/direct/${account.id}");
|
||||
final resp = await apiClient.get("/messager/chat/direct/${account.id}");
|
||||
return SnChatRoom.fromJson(resp.data);
|
||||
} catch (err) {
|
||||
if (err is DioException && err.response?.statusCode == 404) {
|
||||
@@ -812,7 +807,7 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.post(
|
||||
'/sphere/chat/direct',
|
||||
'/messager/chat/direct',
|
||||
data: {'related_user_id': account.value!.id},
|
||||
);
|
||||
final chat = SnChatRoom.fromJson(resp.data);
|
||||
@@ -838,262 +833,256 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
final accountPublishers = ref.watch(accountPublishersProvider(data.id));
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
appBar:
|
||||
isWideScreen(context)
|
||||
? AppBar(
|
||||
foregroundColor: appbarColor.value,
|
||||
leading: PageBackButton(
|
||||
color: appbarColor.value,
|
||||
appBar: isWideScreen(context)
|
||||
? AppBar(
|
||||
foregroundColor: appbarColor.value,
|
||||
leading: PageBackButton(
|
||||
color: appbarColor.value,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(context).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(context).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
body:
|
||||
isWideScreen(context)
|
||||
? Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountBasicInfo(
|
||||
data: data,
|
||||
uname: name,
|
||||
accountDeveloper: accountDeveloper,
|
||||
).padding(horizontal: 4, top: 20),
|
||||
),
|
||||
if (data.badges.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: Card(
|
||||
child: BadgeList(
|
||||
badges: data.badges,
|
||||
).padding(horizontal: 26, vertical: 20),
|
||||
).padding(left: 2, right: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
spacing: 12,
|
||||
children: [
|
||||
LevelingProgressCard(
|
||||
level: data.profile.level,
|
||||
experience: data.profile.experience,
|
||||
progress: data.profile.levelingProgress,
|
||||
).padding(left: 2, right: 4),
|
||||
if (data.profile.verification != null)
|
||||
Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: VerificationStatusCard(
|
||||
mark: data.profile.verification!,
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 4, top: 8),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileBio(
|
||||
data: data,
|
||||
).padding(top: 4),
|
||||
),
|
||||
if (data.profile.links.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileLinks(data: data),
|
||||
),
|
||||
if (data.contacts.any((c) => c.isPublic))
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileContacts(data: data),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileDetail(data: data),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverGap(18),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(
|
||||
uname: name,
|
||||
).padding(horizontal: 4, top: 4, bottom: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountPublisherList(
|
||||
publishers: accountPublishers.value ?? [],
|
||||
),
|
||||
),
|
||||
if (user.value != null && !isCurrentUser)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountAction(
|
||||
data: data,
|
||||
accountRelationship: accountRelationship,
|
||||
accountChat: accountChat,
|
||||
relationshipAction: relationshipAction,
|
||||
blockAction: blockAction,
|
||||
directMessageAction: directMessageAction,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
body: isWideScreen(context)
|
||||
? Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountBasicInfo(
|
||||
data: data,
|
||||
uname: name,
|
||||
accountDeveloper: accountDeveloper,
|
||||
).padding(horizontal: 4, top: 20),
|
||||
),
|
||||
if (data.badges.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: Card(
|
||||
child: FortuneGraphWidget(
|
||||
events: accountEvents,
|
||||
eventCalandarUser: data.name,
|
||||
margin: EdgeInsets.zero,
|
||||
),
|
||||
child: BadgeList(
|
||||
badges: data.badges,
|
||||
).padding(horizontal: 26, vertical: 20),
|
||||
).padding(left: 2, right: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
spacing: 12,
|
||||
children: [
|
||||
LevelingProgressCard(
|
||||
level: data.profile.level,
|
||||
experience: data.profile.experience,
|
||||
progress: data.profile.levelingProgress,
|
||||
).padding(left: 2, right: 4),
|
||||
if (data.profile.verification != null)
|
||||
Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: VerificationStatusCard(
|
||||
mark: data.profile.verification!,
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 4, top: 8),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileBio(
|
||||
data: data,
|
||||
).padding(top: 4),
|
||||
),
|
||||
if (data.profile.links.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileLinks(data: data),
|
||||
),
|
||||
if (data.contacts.any((c) => c.isPublic))
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileContacts(data: data),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileDetail(data: data),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverGap(18),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(
|
||||
uname: name,
|
||||
).padding(horizontal: 4, top: 4, bottom: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountPublisherList(
|
||||
publishers: accountPublishers.value ?? [],
|
||||
),
|
||||
),
|
||||
if (user.value != null && !isCurrentUser)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountAction(
|
||||
data: data,
|
||||
accountRelationship: accountRelationship,
|
||||
accountChat: accountChat,
|
||||
relationshipAction: relationshipAction,
|
||||
blockAction: blockAction,
|
||||
directMessageAction: directMessageAction,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 24)
|
||||
: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
foregroundColor: appbarColor.value,
|
||||
expandedHeight: 180,
|
||||
pinned: true,
|
||||
leading: PageBackButton(
|
||||
color: appbarColor.value,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
flexibleSpace: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child:
|
||||
data.profile.background?.id != null
|
||||
? CloudImageWidget(
|
||||
file: data.profile.background,
|
||||
)
|
||||
: Container(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).appBarTheme.backgroundColor,
|
||||
),
|
||||
),
|
||||
FlexibleSpaceBar(
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(
|
||||
context,
|
||||
).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Card(
|
||||
child: FortuneGraphWidget(
|
||||
events: accountEvents,
|
||||
eventCalandarUser: data.name,
|
||||
margin: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountBasicInfo(
|
||||
data: data,
|
||||
uname: name,
|
||||
accountDeveloper: accountDeveloper,
|
||||
).padding(horizontal: 4, top: 8),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 24)
|
||||
: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
foregroundColor: appbarColor.value,
|
||||
expandedHeight: 180,
|
||||
pinned: true,
|
||||
leading: PageBackButton(
|
||||
color: appbarColor.value,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
if (data.badges.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: Card(
|
||||
child: BadgeList(
|
||||
badges: data.badges,
|
||||
).padding(horizontal: 26, vertical: 20),
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
children: [
|
||||
LevelingProgressCard(
|
||||
level: data.profile.level,
|
||||
experience: data.profile.experience,
|
||||
progress: data.profile.levelingProgress,
|
||||
).padding(top: 8, horizontal: 8, bottom: 4),
|
||||
if (data.profile.verification != null)
|
||||
Card(
|
||||
child: VerificationStatusCard(
|
||||
mark: data.profile.verification!,
|
||||
),
|
||||
).padding(horizontal: 4),
|
||||
],
|
||||
),
|
||||
flexibleSpace: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: data.profile.background != null
|
||||
? CloudImageWidget(
|
||||
file: data.profile.background,
|
||||
)
|
||||
: Container(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).appBarTheme.backgroundColor,
|
||||
),
|
||||
),
|
||||
FlexibleSpaceBar(
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(
|
||||
context,
|
||||
).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileBio(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
if (data.profile.links.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileLinks(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
if (data.contacts.any((c) => c.isPublic))
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileContacts(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(
|
||||
uname: name,
|
||||
).padding(horizontal: 8, top: 4, bottom: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountPublisherList(
|
||||
publishers: accountPublishers.value ?? [],
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileDetail(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
if (user.value != null && !isCurrentUser)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountAction(
|
||||
data: data,
|
||||
accountRelationship: accountRelationship,
|
||||
accountChat: accountChat,
|
||||
relationshipAction: relationshipAction,
|
||||
blockAction: blockAction,
|
||||
directMessageAction: directMessageAction,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountBasicInfo(
|
||||
data: data,
|
||||
uname: name,
|
||||
accountDeveloper: accountDeveloper,
|
||||
).padding(horizontal: 4, top: 8),
|
||||
),
|
||||
if (data.badges.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: Card(
|
||||
child: FortuneGraphWidget(
|
||||
events: accountEvents,
|
||||
eventCalandarUser: data.name,
|
||||
),
|
||||
child: BadgeList(
|
||||
badges: data.badges,
|
||||
).padding(horizontal: 26, vertical: 20),
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
children: [
|
||||
LevelingProgressCard(
|
||||
level: data.profile.level,
|
||||
experience: data.profile.experience,
|
||||
progress: data.profile.levelingProgress,
|
||||
).padding(top: 8, horizontal: 8, bottom: 4),
|
||||
if (data.profile.verification != null)
|
||||
Card(
|
||||
child: VerificationStatusCard(
|
||||
mark: data.profile.verification!,
|
||||
),
|
||||
).padding(horizontal: 4),
|
||||
],
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileBio(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
if (data.profile.links.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileLinks(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
if (data.contacts.any((c) => c.isPublic))
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileContacts(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(
|
||||
uname: name,
|
||||
).padding(horizontal: 8, top: 4, bottom: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountPublisherList(
|
||||
publishers: accountPublishers.value ?? [],
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountProfileDetail(
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
if (user.value != null && !isCurrentUser)
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountAction(
|
||||
data: data,
|
||||
accountRelationship: accountRelationship,
|
||||
accountChat: accountChat,
|
||||
relationshipAction: relationshipAction,
|
||||
blockAction: blockAction,
|
||||
directMessageAction: directMessageAction,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Card(
|
||||
child: FortuneGraphWidget(
|
||||
events: accountEvents,
|
||||
eventCalandarUser: data.name,
|
||||
),
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
error:
|
||||
(error, stackTrace) => AppScaffold(
|
||||
appBar: AppBar(leading: const PageBackButton()),
|
||||
body: Center(child: Text(error.toString())),
|
||||
),
|
||||
loading:
|
||||
() => AppScaffold(
|
||||
appBar: AppBar(leading: const PageBackButton()),
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
error: (error, stackTrace) => AppScaffold(
|
||||
appBar: AppBar(leading: const PageBackButton()),
|
||||
body: Center(child: Text(error.toString())),
|
||||
),
|
||||
loading: () => AppScaffold(
|
||||
appBar: AppBar(leading: const PageBackButton()),
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'profile.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(account)
|
||||
const accountProvider = AccountFamily._();
|
||||
final accountProvider = AccountFamily._();
|
||||
|
||||
final class AccountProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class AccountProvider
|
||||
FutureOr<SnAccount>
|
||||
>
|
||||
with $FutureModifier<SnAccount>, $FutureProvider<SnAccount> {
|
||||
const AccountProvider._({
|
||||
AccountProvider._({
|
||||
required AccountFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -67,7 +67,7 @@ String _$accountHash() => r'5e2b7bd59151b4638a5561f495537c259f767123';
|
||||
|
||||
final class AccountFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnAccount>, String> {
|
||||
const AccountFamily._()
|
||||
AccountFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'accountProvider',
|
||||
@@ -84,7 +84,7 @@ final class AccountFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(accountBadges)
|
||||
const accountBadgesProvider = AccountBadgesFamily._();
|
||||
final accountBadgesProvider = AccountBadgesFamily._();
|
||||
|
||||
final class AccountBadgesProvider
|
||||
extends
|
||||
@@ -96,7 +96,7 @@ final class AccountBadgesProvider
|
||||
with
|
||||
$FutureModifier<List<SnAccountBadge>>,
|
||||
$FutureProvider<List<SnAccountBadge>> {
|
||||
const AccountBadgesProvider._({
|
||||
AccountBadgesProvider._({
|
||||
required AccountBadgesFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -144,7 +144,7 @@ String _$accountBadgesHash() => r'68db63f49827020beecbdbf20529520d0cd14a7d';
|
||||
|
||||
final class AccountBadgesFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<SnAccountBadge>>, String> {
|
||||
const AccountBadgesFamily._()
|
||||
AccountBadgesFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'accountBadgesProvider',
|
||||
@@ -161,13 +161,13 @@ final class AccountBadgesFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(accountAppbarForcegroundColor)
|
||||
const accountAppbarForcegroundColorProvider =
|
||||
final accountAppbarForcegroundColorProvider =
|
||||
AccountAppbarForcegroundColorFamily._();
|
||||
|
||||
final class AccountAppbarForcegroundColorProvider
|
||||
extends $FunctionalProvider<AsyncValue<Color?>, Color?, FutureOr<Color?>>
|
||||
with $FutureModifier<Color?>, $FutureProvider<Color?> {
|
||||
const AccountAppbarForcegroundColorProvider._({
|
||||
AccountAppbarForcegroundColorProvider._({
|
||||
required AccountAppbarForcegroundColorFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -212,11 +212,11 @@ final class AccountAppbarForcegroundColorProvider
|
||||
}
|
||||
|
||||
String _$accountAppbarForcegroundColorHash() =>
|
||||
r'127fcc7fd6ec6a41ac4a6975276b5271aa4fa7d0';
|
||||
r'59e0049a5158ea653f0afd724df9ff2312b90050';
|
||||
|
||||
final class AccountAppbarForcegroundColorFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<Color?>, String> {
|
||||
const AccountAppbarForcegroundColorFamily._()
|
||||
AccountAppbarForcegroundColorFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'accountAppbarForcegroundColorProvider',
|
||||
@@ -233,7 +233,7 @@ final class AccountAppbarForcegroundColorFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(accountDirectChat)
|
||||
const accountDirectChatProvider = AccountDirectChatFamily._();
|
||||
final accountDirectChatProvider = AccountDirectChatFamily._();
|
||||
|
||||
final class AccountDirectChatProvider
|
||||
extends
|
||||
@@ -243,7 +243,7 @@ final class AccountDirectChatProvider
|
||||
FutureOr<SnChatRoom?>
|
||||
>
|
||||
with $FutureModifier<SnChatRoom?>, $FutureProvider<SnChatRoom?> {
|
||||
const AccountDirectChatProvider._({
|
||||
AccountDirectChatProvider._({
|
||||
required AccountDirectChatFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -287,11 +287,11 @@ final class AccountDirectChatProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$accountDirectChatHash() => r'149ea3a3730672cfbbb8c16fe1f2caa0bb9f0e17';
|
||||
String _$accountDirectChatHash() => r'71bc9eed34a436a3743e8ef87f7aaae861fc5746';
|
||||
|
||||
final class AccountDirectChatFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnChatRoom?>, String> {
|
||||
const AccountDirectChatFamily._()
|
||||
AccountDirectChatFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'accountDirectChatProvider',
|
||||
@@ -308,7 +308,7 @@ final class AccountDirectChatFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(accountRelationship)
|
||||
const accountRelationshipProvider = AccountRelationshipFamily._();
|
||||
final accountRelationshipProvider = AccountRelationshipFamily._();
|
||||
|
||||
final class AccountRelationshipProvider
|
||||
extends
|
||||
@@ -318,7 +318,7 @@ final class AccountRelationshipProvider
|
||||
FutureOr<SnRelationship?>
|
||||
>
|
||||
with $FutureModifier<SnRelationship?>, $FutureProvider<SnRelationship?> {
|
||||
const AccountRelationshipProvider._({
|
||||
AccountRelationshipProvider._({
|
||||
required AccountRelationshipFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -367,7 +367,7 @@ String _$accountRelationshipHash() =>
|
||||
|
||||
final class AccountRelationshipFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnRelationship?>, String> {
|
||||
const AccountRelationshipFamily._()
|
||||
AccountRelationshipFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'accountRelationshipProvider',
|
||||
@@ -384,7 +384,7 @@ final class AccountRelationshipFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(accountBotDeveloper)
|
||||
const accountBotDeveloperProvider = AccountBotDeveloperFamily._();
|
||||
final accountBotDeveloperProvider = AccountBotDeveloperFamily._();
|
||||
|
||||
final class AccountBotDeveloperProvider
|
||||
extends
|
||||
@@ -394,7 +394,7 @@ final class AccountBotDeveloperProvider
|
||||
FutureOr<SnDeveloper?>
|
||||
>
|
||||
with $FutureModifier<SnDeveloper?>, $FutureProvider<SnDeveloper?> {
|
||||
const AccountBotDeveloperProvider._({
|
||||
AccountBotDeveloperProvider._({
|
||||
required AccountBotDeveloperFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -443,7 +443,7 @@ String _$accountBotDeveloperHash() =>
|
||||
|
||||
final class AccountBotDeveloperFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnDeveloper?>, String> {
|
||||
const AccountBotDeveloperFamily._()
|
||||
AccountBotDeveloperFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'accountBotDeveloperProvider',
|
||||
@@ -460,7 +460,7 @@ final class AccountBotDeveloperFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(accountPublishers)
|
||||
const accountPublishersProvider = AccountPublishersFamily._();
|
||||
final accountPublishersProvider = AccountPublishersFamily._();
|
||||
|
||||
final class AccountPublishersProvider
|
||||
extends
|
||||
@@ -472,7 +472,7 @@ final class AccountPublishersProvider
|
||||
with
|
||||
$FutureModifier<List<SnPublisher>>,
|
||||
$FutureProvider<List<SnPublisher>> {
|
||||
const AccountPublishersProvider._({
|
||||
AccountPublishersProvider._({
|
||||
required AccountPublishersFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -520,7 +520,7 @@ String _$accountPublishersHash() => r'25f5695b4a5154163d77f1769876d826bf736609';
|
||||
|
||||
final class AccountPublishersFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<SnPublisher>>, String> {
|
||||
const AccountPublishersFamily._()
|
||||
AccountPublishersFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'accountPublishersProvider',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -29,12 +31,28 @@ Future<List<SnRelationship>> sentFriendRequest(Ref ref) async {
|
||||
.toList();
|
||||
}
|
||||
|
||||
final relationshipListNotifierProvider = AsyncNotifierProvider.autoDispose(
|
||||
RelationshipListNotifier.new,
|
||||
);
|
||||
final relationshipListNotifierProvider =
|
||||
AsyncNotifierProvider.autoDispose<
|
||||
RelationshipListNotifier,
|
||||
PaginationState<SnRelationship>
|
||||
>(RelationshipListNotifier.new);
|
||||
|
||||
class RelationshipListNotifier extends AsyncNotifier<List<SnRelationship>>
|
||||
class RelationshipListNotifier
|
||||
extends AsyncNotifier<PaginationState<SnRelationship>>
|
||||
with AsyncPaginationController<SnRelationship> {
|
||||
@override
|
||||
FutureOr<PaginationState<SnRelationship>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SnRelationship>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
@@ -95,7 +113,7 @@ class RelationshipListTile extends StatelessWidget {
|
||||
contentPadding: const EdgeInsets.only(left: 16, right: 12),
|
||||
leading: AccountPfcGestureDetector(
|
||||
uname: account.name,
|
||||
child: ProfilePictureWidget(fileId: account.profile.picture?.id),
|
||||
child: ProfilePictureWidget(file: account.profile.picture),
|
||||
),
|
||||
title: Row(
|
||||
spacing: 6,
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'relationship.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(sentFriendRequest)
|
||||
const sentFriendRequestProvider = SentFriendRequestProvider._();
|
||||
final sentFriendRequestProvider = SentFriendRequestProvider._();
|
||||
|
||||
final class SentFriendRequestProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class SentFriendRequestProvider
|
||||
with
|
||||
$FutureModifier<List<SnRelationship>>,
|
||||
$FutureProvider<List<SnRelationship>> {
|
||||
const SentFriendRequestProvider._()
|
||||
SentFriendRequestProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
|
||||
180
lib/screens/activitypub/search.dart
Normal file
180
lib/screens/activitypub/search.dart
Normal file
@@ -0,0 +1,180 @@
|
||||
import 'dart:async';
|
||||
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:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/activitypub.dart';
|
||||
import 'package:island/services/activitypub_service.dart';
|
||||
import 'package:island/widgets/activitypub/actor_list_item.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
class ApSearchScreen extends HookConsumerWidget {
|
||||
const ApSearchScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final searchController = useTextEditingController();
|
||||
final debounce = useMemoized(() => const Duration(milliseconds: 500));
|
||||
final debounceTimer = useRef<Timer?>(null);
|
||||
final searchResults = useState<List<SnActivityPubActor>>([]);
|
||||
final isSearching = useState(false);
|
||||
|
||||
useEffect(() {
|
||||
return () {
|
||||
searchController.dispose();
|
||||
debounceTimer.value?.cancel();
|
||||
};
|
||||
}, []);
|
||||
|
||||
Future<void> performSearch(String query) async {
|
||||
if (query.trim().isEmpty) {
|
||||
searchResults.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
isSearching.value = true;
|
||||
try {
|
||||
final service = ref.read(activityPubServiceProvider);
|
||||
final results = await service.searchUsers(query);
|
||||
searchResults.value = results;
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
isSearching.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void onSearchChanged(String query) {
|
||||
if (debounceTimer.value?.isActive ?? false) {
|
||||
debounceTimer.value!.cancel();
|
||||
}
|
||||
debounceTimer.value = Timer(debounce, () {
|
||||
performSearch(query);
|
||||
});
|
||||
}
|
||||
|
||||
void updateActorIsFollowing(String actorId, bool isFollowing) {
|
||||
searchResults.value = searchResults.value
|
||||
.map(
|
||||
(a) => a.id == actorId ? a.copyWith(isFollowing: isFollowing) : a,
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<void> handleFollow(SnActivityPubActor actor) async {
|
||||
try {
|
||||
updateActorIsFollowing(actor.id, true);
|
||||
final service = ref.read(activityPubServiceProvider);
|
||||
await service.followRemoteUser(actor.uri);
|
||||
showSnackBar(
|
||||
'followedUser'.tr(
|
||||
args: [
|
||||
'${actor.username?.isNotEmpty ?? false ? actor.username : actor.displayName}',
|
||||
],
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
updateActorIsFollowing(actor.id, false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleUnfollow(SnActivityPubActor actor) async {
|
||||
try {
|
||||
updateActorIsFollowing(actor.id, false);
|
||||
final service = ref.read(activityPubServiceProvider);
|
||||
await service.unfollowRemoteUser(actor.uri);
|
||||
showSnackBar(
|
||||
'unfollowedUser'.tr(
|
||||
args: [
|
||||
'${actor.username?.isNotEmpty ?? false ? actor.username : actor.displayName}',
|
||||
],
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
updateActorIsFollowing(actor.id, true);
|
||||
}
|
||||
}
|
||||
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
appBar: AppBar(title: Text('searchFediverse'.tr()), elevation: 0),
|
||||
body: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SearchBar(
|
||||
controller: searchController,
|
||||
hintText: 'searchFediverseHint'.tr(
|
||||
args: ['@username@instance.com'],
|
||||
),
|
||||
leading: const Icon(Symbols.search).padding(horizontal: 24),
|
||||
onChanged: onSearchChanged,
|
||||
onSubmitted: (value) {
|
||||
onSearchChanged(value);
|
||||
performSearch(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: isSearching.value
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: searchResults.value.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.search,
|
||||
size: 64,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (searchController.text.isEmpty)
|
||||
Text(
|
||||
'searchFediverseEmpty'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
)
|
||||
else
|
||||
Text(
|
||||
'searchFediverseNoResults'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: ExtendedRefreshIndicator(
|
||||
onRefresh: () => performSearch(searchController.text),
|
||||
child: ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
itemCount: searchResults.value.length,
|
||||
separatorBuilder: (context, index) => const Gap(8),
|
||||
itemBuilder: (context, index) {
|
||||
final actor = searchResults.value[index];
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 560),
|
||||
child: ApActorListItem(
|
||||
actor: actor,
|
||||
isFollowing: actor.isFollowing ?? false,
|
||||
isLoading: false,
|
||||
onFollow: () => handleFollow(actor),
|
||||
onUnfollow: () => handleUnfollow(actor),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,12 @@ part of 'captcha.config.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(captchaUrl)
|
||||
const captchaUrlProvider = CaptchaUrlProvider._();
|
||||
final captchaUrlProvider = CaptchaUrlProvider._();
|
||||
|
||||
final class CaptchaUrlProvider
|
||||
extends $FunctionalProvider<AsyncValue<String>, String, FutureOr<String>>
|
||||
with $FutureModifier<String>, $FutureProvider<String> {
|
||||
const CaptchaUrlProvider._()
|
||||
CaptchaUrlProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
|
||||
@@ -69,11 +69,11 @@ class CallScreen extends HookConsumerWidget {
|
||||
callState.isConnected
|
||||
? formatDuration(callState.duration)
|
||||
: (switch (callNotifier.room?.connectionState) {
|
||||
ConnectionState.connected => 'connected',
|
||||
ConnectionState.connecting => 'connecting',
|
||||
ConnectionState.reconnecting => 'reconnecting',
|
||||
_ => 'disconnected',
|
||||
}).tr(),
|
||||
ConnectionState.connected => 'connected',
|
||||
ConnectionState.connecting => 'connecting',
|
||||
ConnectionState.reconnecting => 'reconnecting',
|
||||
_ => 'disconnected',
|
||||
}).tr(),
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
@@ -92,40 +92,40 @@ class CallScreen extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
body:
|
||||
callState.error != null
|
||||
? Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 320),
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Symbols.error_outline, size: 48),
|
||||
const Gap(4),
|
||||
Text(
|
||||
callState.error!,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Color(0xFF757575)),
|
||||
),
|
||||
const Gap(8),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
callNotifier.disconnect();
|
||||
callNotifier.dispose();
|
||||
callNotifier.joinRoom(room);
|
||||
},
|
||||
child: Text('retry').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: callState.error != null
|
||||
? Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 320),
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Symbols.error_outline, size: 48),
|
||||
const Gap(4),
|
||||
Text(
|
||||
callState.error!,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Color(0xFF757575)),
|
||||
),
|
||||
const Gap(8),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
callNotifier.disconnect();
|
||||
callNotifier.dispose();
|
||||
callNotifier.joinRoom(room);
|
||||
},
|
||||
child: Text('retry').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
Expanded(child: CallContent()),
|
||||
CallControlsBar(),
|
||||
Gap(MediaQuery.of(context).padding.bottom + 16),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
const SizedBox(width: double.infinity),
|
||||
Expanded(child: CallContent()),
|
||||
CallControlsBar(popOnLeaves: true),
|
||||
Gap(MediaQuery.of(context).padding.bottom + 16),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,17 @@ import 'package:island/models/chat.dart';
|
||||
import 'package:island/pods/chat/chat_summary.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/screens/chat/chat_form.dart';
|
||||
import 'package:island/screens/realm/realms.dart';
|
||||
import 'package:island/services/event_bus.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/account/account_picker.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/chat_room_widgets.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:island/widgets/navigation/fab_menu.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
@@ -72,123 +74,155 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
||||
.where((item) => !item.isPinned)
|
||||
.toList();
|
||||
|
||||
return RefreshIndicator(
|
||||
return ExtendedRefreshIndicator(
|
||||
onRefresh: () => Future.sync(() {
|
||||
ref.invalidate(chatRoomJoinedProvider);
|
||||
}),
|
||||
child: Column(
|
||||
children: [
|
||||
// Always show pinned chats in their own section
|
||||
if (pinnedItems.isNotEmpty)
|
||||
ExpansionTile(
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer.withOpacity(0.5),
|
||||
collapsedBackgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer.withOpacity(0.5),
|
||||
title: Text('pinnedChatRoom'.tr()),
|
||||
leading: const Icon(Symbols.keep, fill: 1),
|
||||
tilePadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
initiallyExpanded: true,
|
||||
children: [
|
||||
for (final item in pinnedItems)
|
||||
ChatRoomListTile(
|
||||
room: item,
|
||||
isDirect: item.type == 1,
|
||||
onTap: () {
|
||||
if (isWideScreen(context)) {
|
||||
context.replaceNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
} else {
|
||||
context.pushNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
child: Theme(
|
||||
data: Theme.of(
|
||||
context,
|
||||
).copyWith(dividerColor: Colors.transparent),
|
||||
child: Column(
|
||||
children: [
|
||||
// Always show pinned chats in their own section
|
||||
if (pinnedItems.isNotEmpty)
|
||||
ExpansionTile(
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerHighest
|
||||
.withOpacity(0.5),
|
||||
collapsedBackgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer.withOpacity(0.5),
|
||||
title: Text('pinnedChatRoom'.tr()),
|
||||
leading: const Icon(Symbols.keep, fill: 1),
|
||||
tilePadding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
initiallyExpanded: true,
|
||||
children: [
|
||||
for (final item in pinnedItems)
|
||||
ChatRoomListTile(
|
||||
room: item,
|
||||
isDirect: item.type == 1,
|
||||
onTap: () {
|
||||
if (isWideScreen(context)) {
|
||||
context.replaceNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
} else {
|
||||
context.pushNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final summaries =
|
||||
ref
|
||||
.watch(chatSummaryProvider)
|
||||
.whenData((data) => data)
|
||||
.value ??
|
||||
{};
|
||||
|
||||
if (settings.groupedChatList &&
|
||||
selectedTab.value == 0) {
|
||||
// Group by realm (include both pinned and unpinned)
|
||||
final realmGroups = <String?, List<SnChatRoom>>{};
|
||||
final ungrouped = <SnChatRoom>[];
|
||||
|
||||
for (final item in filteredItems) {
|
||||
if (item.realmId != null) {
|
||||
realmGroups
|
||||
.putIfAbsent(item.realmId, () => [])
|
||||
.add(item);
|
||||
} else if (!item.isPinned) {
|
||||
// Only unpinned chats without realm go to ungrouped
|
||||
ungrouped.add(item);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final summaries =
|
||||
ref
|
||||
.watch(chatSummaryProvider)
|
||||
.whenData((data) => data)
|
||||
.value ??
|
||||
{};
|
||||
|
||||
if (settings.groupedChatList &&
|
||||
selectedTab.value == 0) {
|
||||
// Group by realm (include both pinned and unpinned)
|
||||
final realmGroups = <String?, List<SnChatRoom>>{};
|
||||
final ungrouped = <SnChatRoom>[];
|
||||
|
||||
for (final item in filteredItems) {
|
||||
if (item.realmId != null) {
|
||||
realmGroups
|
||||
.putIfAbsent(item.realmId, () => [])
|
||||
.add(item);
|
||||
} else if (!item.isPinned) {
|
||||
// Only unpinned chats without realm go to ungrouped
|
||||
ungrouped.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
final children = <Widget>[];
|
||||
final children = <Widget>[];
|
||||
|
||||
// Add realm groups
|
||||
for (final entry in realmGroups.entries) {
|
||||
final rooms = entry.value;
|
||||
final realm = rooms.first.realm;
|
||||
final realmName = realm?.name ?? 'Unknown Realm';
|
||||
// Add realm groups
|
||||
for (final entry in realmGroups.entries) {
|
||||
final rooms = entry.value;
|
||||
final realm = rooms.first.realm;
|
||||
final realmName =
|
||||
realm?.name ?? 'Unknown Realm';
|
||||
|
||||
// Calculate total unread count for this realm
|
||||
final totalUnread = rooms.fold<int>(
|
||||
0,
|
||||
(sum, room) =>
|
||||
sum +
|
||||
(summaries[room.id]?.unreadCount ?? 0),
|
||||
);
|
||||
// Calculate total unread count for this realm
|
||||
final totalUnread = rooms.fold<int>(
|
||||
0,
|
||||
(sum, room) =>
|
||||
sum +
|
||||
(summaries[room.id]?.unreadCount ?? 0),
|
||||
);
|
||||
|
||||
children.add(
|
||||
ExpansionTile(
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainer
|
||||
.withOpacity(0.5),
|
||||
collapsedBackgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainer
|
||||
.withOpacity(0.5),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(child: Text(realmName)),
|
||||
Badge(
|
||||
isLabelVisible: totalUnread > 0,
|
||||
label: Text(totalUnread.toString()),
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary,
|
||||
textColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.onPrimary,
|
||||
),
|
||||
],
|
||||
children.add(
|
||||
ExpansionTile(
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerHighest
|
||||
.withOpacity(0.5),
|
||||
collapsedBackgroundColor:
|
||||
Colors.transparent,
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(child: Text(realmName)),
|
||||
Badge(
|
||||
isLabelVisible: totalUnread > 0,
|
||||
label: Text(totalUnread.toString()),
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary,
|
||||
textColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.onPrimary,
|
||||
),
|
||||
],
|
||||
),
|
||||
leading: ProfilePictureWidget(
|
||||
file: realm?.picture,
|
||||
radius: 16,
|
||||
),
|
||||
tilePadding: const EdgeInsets.only(
|
||||
left: 20,
|
||||
right: 24,
|
||||
),
|
||||
children: rooms.map((room) {
|
||||
return ChatRoomListTile(
|
||||
room: room,
|
||||
isDirect: room.type == 1,
|
||||
onTap: () {
|
||||
if (isWideScreen(context)) {
|
||||
context.replaceNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': room.id},
|
||||
);
|
||||
} else {
|
||||
context.pushNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': room.id},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
leading: ProfilePictureWidget(
|
||||
file: realm?.picture,
|
||||
radius: 16,
|
||||
),
|
||||
tilePadding: const EdgeInsets.only(
|
||||
left: 20,
|
||||
right: 24,
|
||||
),
|
||||
children: rooms.map((room) {
|
||||
);
|
||||
}
|
||||
|
||||
// Add ungrouped chats
|
||||
if (ungrouped.isNotEmpty) {
|
||||
children.addAll(
|
||||
ungrouped.map((room) {
|
||||
return ChatRoomListTile(
|
||||
room: room,
|
||||
isDirect: room.type == 1,
|
||||
@@ -206,80 +240,55 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Add ungrouped chats
|
||||
if (ungrouped.isNotEmpty) {
|
||||
children.addAll(
|
||||
ungrouped.map((room) {
|
||||
return ListView(
|
||||
padding: EdgeInsets.only(bottom: 96),
|
||||
children: children,
|
||||
);
|
||||
} else {
|
||||
// Normal list view
|
||||
return SuperListView.builder(
|
||||
padding: EdgeInsets.only(bottom: 96),
|
||||
itemCount: unpinnedItems
|
||||
.where(
|
||||
(item) =>
|
||||
selectedTab.value == 0 ||
|
||||
(selectedTab.value == 1 &&
|
||||
item.type == 1) ||
|
||||
(selectedTab.value == 2 &&
|
||||
item.type != 1),
|
||||
)
|
||||
.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = unpinnedItems[index];
|
||||
return ChatRoomListTile(
|
||||
room: room,
|
||||
isDirect: room.type == 1,
|
||||
room: item,
|
||||
isDirect: item.type == 1,
|
||||
onTap: () {
|
||||
if (isWideScreen(context)) {
|
||||
context.replaceNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': room.id},
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
} else {
|
||||
context.pushNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': room.id},
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return ListView(
|
||||
padding: EdgeInsets.only(bottom: 96),
|
||||
children: children,
|
||||
);
|
||||
} else {
|
||||
// Normal list view
|
||||
return SuperListView.builder(
|
||||
padding: EdgeInsets.only(bottom: 96),
|
||||
itemCount: unpinnedItems
|
||||
.where(
|
||||
(item) =>
|
||||
selectedTab.value == 0 ||
|
||||
(selectedTab.value == 1 &&
|
||||
item.type == 1) ||
|
||||
(selectedTab.value == 2 &&
|
||||
item.type != 1),
|
||||
)
|
||||
.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = unpinnedItems[index];
|
||||
return ChatRoomListTile(
|
||||
room: item,
|
||||
isDirect: item.type == 1,
|
||||
onTap: () {
|
||||
if (isWideScreen(context)) {
|
||||
context.replaceNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
} else {
|
||||
context.pushNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {'id': item.id},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -372,23 +381,6 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
};
|
||||
}, [tabController]);
|
||||
|
||||
useEffect(() {
|
||||
// Set FAB type to chat
|
||||
final fabMenuNotifier = ref.read(fabMenuTypeProvider.notifier);
|
||||
Future(() {
|
||||
fabMenuNotifier.setMenuType(FabMenuType.chat);
|
||||
});
|
||||
return () {
|
||||
// Clean up: reset FAB type to main
|
||||
final fabMenu = ref.read(fabMenuTypeProvider);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (fabMenu == FabMenuType.chat) {
|
||||
fabMenuNotifier.setMenuType(FabMenuType.main);
|
||||
}
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (isAside) {
|
||||
return Card(
|
||||
margin: EdgeInsets.zero,
|
||||
@@ -461,8 +453,74 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
|
||||
final appbarFeColor = Theme.of(context).appBarTheme.foregroundColor;
|
||||
|
||||
final userInfo = ref.watch(userInfoProvider);
|
||||
|
||||
return AppScaffold(
|
||||
extendBody: false, // Prevent conflicts with tabs navigation
|
||||
floatingActionButton: userInfo.value != null
|
||||
? FloatingActionButton(
|
||||
child: const Icon(Symbols.add),
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: true,
|
||||
builder: (context) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Gap(40),
|
||||
ListTile(
|
||||
title: const Text('createChatRoom').tr(),
|
||||
leading: const Icon(Symbols.add),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => const EditChatScreen(),
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
eventBus.fire(const ChatRoomsRefreshEvent());
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('createDirectMessage').tr(),
|
||||
leading: const Icon(Symbols.person),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
onTap: () async {
|
||||
final result = await showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => const AccountPickerSheet(),
|
||||
);
|
||||
if (result == null) return;
|
||||
final client = ref.read(apiClientProvider);
|
||||
try {
|
||||
await client.post(
|
||||
'/messager/chat/direct',
|
||||
data: {'related_user_id': result.id},
|
||||
);
|
||||
eventBus.fire(const ChatRoomsRefreshEvent());
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
}
|
||||
},
|
||||
),
|
||||
const Gap(16),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
).padding(bottom: MediaQuery.of(context).padding.bottom)
|
||||
: null,
|
||||
appBar: AppBar(
|
||||
flexibleSpace: Container(
|
||||
height: 48,
|
||||
@@ -541,11 +599,13 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
body: ChatListBodyWidget(
|
||||
isFloating: false,
|
||||
tabController: tabController,
|
||||
selectedTab: selectedTab,
|
||||
),
|
||||
body: userInfo.value == null
|
||||
? const ResponseUnauthorizedWidget()
|
||||
: ChatListBodyWidget(
|
||||
isFloating: false,
|
||||
tabController: tabController,
|
||||
selectedTab: selectedTab,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -560,7 +620,9 @@ class _ChatInvitesSheet extends HookConsumerWidget {
|
||||
Future<void> acceptInvite(SnChatMember invite) async {
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept');
|
||||
await client.post(
|
||||
'/messager/chat/invites/${invite.chatRoom!.id}/accept',
|
||||
);
|
||||
ref.invalidate(chatroomInvitesProvider);
|
||||
ref.invalidate(chatRoomJoinedProvider);
|
||||
} catch (err) {
|
||||
@@ -572,7 +634,7 @@ class _ChatInvitesSheet extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
await client.post(
|
||||
'/sphere/chat/invites/${invite.chatRoom!.id}/decline',
|
||||
'/messager/chat/invites/${invite.chatRoom!.id}/decline',
|
||||
);
|
||||
ref.invalidate(chatroomInvitesProvider);
|
||||
} catch (err) {
|
||||
|
||||
@@ -97,14 +97,10 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
final cloudFile =
|
||||
await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
).future;
|
||||
final cloudFile = await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(data: result, type: UniversalFileType.image),
|
||||
).future;
|
||||
if (cloudFile == null) {
|
||||
throw ArgumentError('Failed to upload the file...');
|
||||
}
|
||||
@@ -129,7 +125,7 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.request(
|
||||
id == null ? '/sphere/chat' : '/sphere/chat/$id',
|
||||
id == null ? '/messager/chat' : '/messager/chat/$id',
|
||||
data: {
|
||||
'name': nameController.text,
|
||||
'description': descriptionController.text,
|
||||
@@ -166,13 +162,12 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
child:
|
||||
background.value != null
|
||||
? CloudFileWidget(
|
||||
item: background.value!,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
child: background.value != null
|
||||
? CloudFileWidget(
|
||||
item: background.value!,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
onTap: () {
|
||||
setPicture('background');
|
||||
@@ -183,7 +178,7 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
bottom: -32,
|
||||
child: GestureDetector(
|
||||
child: ProfilePictureWidget(
|
||||
fileId: picture.value?.id,
|
||||
file: picture.value,
|
||||
radius: 40,
|
||||
fallbackIcon: Symbols.group,
|
||||
),
|
||||
@@ -208,8 +203,8 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
@@ -223,8 +218,8 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
),
|
||||
minLines: 3,
|
||||
maxLines: null,
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
DropdownButtonFormField<SnRealm>(
|
||||
@@ -241,22 +236,20 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
child: Text('none'.tr()),
|
||||
),
|
||||
...joinedRealms.maybeWhen(
|
||||
data:
|
||||
(realms) => realms.map(
|
||||
(realm) => DropdownMenuItem(
|
||||
value: realm,
|
||||
child: Text(realm.name),
|
||||
),
|
||||
),
|
||||
data: (realms) => realms.map(
|
||||
(realm) => DropdownMenuItem(
|
||||
value: realm,
|
||||
child: Text(realm.name),
|
||||
),
|
||||
),
|
||||
orElse: () => [],
|
||||
),
|
||||
],
|
||||
onChanged:
|
||||
joinedRealms.isLoading
|
||||
? null
|
||||
: (SnRealm? value) {
|
||||
currentRealm.value = value;
|
||||
},
|
||||
onChanged: joinedRealms.isLoading
|
||||
? null
|
||||
: (SnRealm? value) {
|
||||
currentRealm.value = value;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Card(
|
||||
|
||||
@@ -65,8 +65,9 @@ class PublicRoomPreview extends HookConsumerWidget {
|
||||
extentEstimation: (_, _) => 40,
|
||||
itemBuilder: (context, index) {
|
||||
final message = messageList[index];
|
||||
final nextMessage =
|
||||
index < messageList.length - 1 ? messageList[index + 1] : null;
|
||||
final nextMessage = index < messageList.length - 1
|
||||
? messageList[index + 1]
|
||||
: null;
|
||||
final isLastInGroup =
|
||||
nextMessage == null ||
|
||||
nextMessage.senderId != message.senderId ||
|
||||
@@ -97,25 +98,23 @@ class PublicRoomPreview extends HookConsumerWidget {
|
||||
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),
|
||||
),
|
||||
child: (room.type == 1 && room.picture == null)
|
||||
? SplitAvatarWidget(
|
||||
files: room.members!
|
||||
.map((e) => e.account.profile.picture)
|
||||
.toList(),
|
||||
)
|
||||
: room.picture != null
|
||||
? ProfilePictureWidget(
|
||||
file: room.picture,
|
||||
fallbackIcon: Symbols.chat,
|
||||
)
|
||||
: CircleAvatar(
|
||||
child: Text(
|
||||
room.name![0].toUpperCase(),
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
(room.type == 1 && room.name == null)
|
||||
@@ -132,25 +131,23 @@ class PublicRoomPreview extends HookConsumerWidget {
|
||||
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),
|
||||
),
|
||||
child: (room.type == 1 && room.picture == null)
|
||||
? SplitAvatarWidget(
|
||||
files: room.members!
|
||||
.map((e) => e.account.profile.picture)
|
||||
.toList(),
|
||||
)
|
||||
: room.picture != null
|
||||
? ProfilePictureWidget(
|
||||
file: room.picture,
|
||||
fallbackIcon: Symbols.chat,
|
||||
)
|
||||
: CircleAvatar(
|
||||
child: Text(
|
||||
room.name![0].toUpperCase(),
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
(room.type == 1 && room.name == null)
|
||||
@@ -181,17 +178,14 @@ class PublicRoomPreview extends HookConsumerWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: messages.when(
|
||||
data:
|
||||
(messageList) =>
|
||||
messageList.isEmpty
|
||||
? Center(child: Text('No messages yet'.tr()))
|
||||
: chatMessageListWidget(messageList),
|
||||
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(),
|
||||
),
|
||||
error: (error, _) => ResponseErrorWidget(
|
||||
error: error,
|
||||
onRetry: () => messagesNotifier.loadInitial(),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Join button at the bottom for public rooms
|
||||
@@ -202,7 +196,7 @@ class PublicRoomPreview extends HookConsumerWidget {
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
||||
await apiClient.post('/messager/chat/${room.id}/members/me');
|
||||
ref.invalidate(chatRoomIdentityProvider(id));
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
|
||||
@@ -48,6 +48,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
final chatRoom = ref.watch(chatRoomProvider(id));
|
||||
final chatIdentity = ref.watch(chatRoomIdentityProvider(id));
|
||||
final isSyncing = ref.watch(chatSyncingProvider);
|
||||
@@ -71,67 +72,64 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
return AppScaffold(
|
||||
appBar: AppBar(leading: const PageBackButton()),
|
||||
body: Center(
|
||||
child:
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 280),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
room.isCommunity == true
|
||||
? Symbols.person_add
|
||||
: Symbols.person_remove,
|
||||
size: 36,
|
||||
fill: 1,
|
||||
).padding(bottom: 4),
|
||||
Text('chatNotJoined').tr(),
|
||||
if (room.isCommunity != true)
|
||||
Text(
|
||||
'chatUnableJoin',
|
||||
textAlign: TextAlign.center,
|
||||
).tr().bold()
|
||||
else
|
||||
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),
|
||||
).padding(top: 8),
|
||||
],
|
||||
),
|
||||
).center(),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 280),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
room.isCommunity == true
|
||||
? Symbols.person_add
|
||||
: Symbols.person_remove,
|
||||
size: 36,
|
||||
fill: 1,
|
||||
).padding(bottom: 4),
|
||||
Text('chatNotJoined').tr(),
|
||||
if (room.isCommunity != true)
|
||||
Text(
|
||||
'chatUnableJoin',
|
||||
textAlign: TextAlign.center,
|
||||
).tr().bold()
|
||||
else
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () async {
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
await apiClient.post(
|
||||
'/messager/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),
|
||||
).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)),
|
||||
),
|
||||
),
|
||||
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)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -186,10 +184,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
case MessageItemAction.edit:
|
||||
messageEditingTo.value = message.toRemoteMessage();
|
||||
messageController.text = messageEditingTo.value?.content ?? '';
|
||||
attachments.value =
|
||||
messageEditingTo.value!.attachments
|
||||
.map((e) => UniversalFile.fromAttachment(e))
|
||||
.toList();
|
||||
attachments.value = messageEditingTo.value!.attachments
|
||||
.map((e) => UniversalFile.fromAttachment(e))
|
||||
.toList();
|
||||
case MessageItemAction.forward:
|
||||
messageForwardingTo.value = message.toRemoteMessage();
|
||||
case MessageItemAction.reply:
|
||||
@@ -424,38 +421,37 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
label: Text('${(onlineCount.value ?? 0)}'),
|
||||
textStyle: GoogleFonts.robotoMono(fontSize: 10),
|
||||
textColor: Colors.white,
|
||||
backgroundColor:
|
||||
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey,
|
||||
backgroundColor: (onlineCount.value ?? 0) > 1
|
||||
? Colors.green
|
||||
: Colors.grey,
|
||||
offset: Offset(6, 14),
|
||||
child: SizedBox(
|
||||
height: 26,
|
||||
width: 26,
|
||||
child:
|
||||
(room!.type == 1 && room.picture?.id == null)
|
||||
? SplitAvatarWidget(
|
||||
filesId:
|
||||
getValidMembers(
|
||||
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),
|
||||
),
|
||||
child: (room!.type == 1 && room.picture == null)
|
||||
? SplitAvatarWidget(
|
||||
files: getValidMembers(
|
||||
room.members!,
|
||||
).map((e) => e.account.profile.picture).toList(),
|
||||
)
|
||||
: room.picture != null
|
||||
? ProfilePictureWidget(
|
||||
file: room.picture,
|
||||
fallbackIcon: Symbols.chat,
|
||||
)
|
||||
: CircleAvatar(
|
||||
child: Text(
|
||||
room.name![0].toUpperCase(),
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
(room.type == 1 && room.name == null)
|
||||
? getValidMembers(
|
||||
room.members!,
|
||||
).map((e) => e.account.nick).join(', ')
|
||||
room.members!,
|
||||
).map((e) => e.account.nick).join(', ')
|
||||
: room.name!,
|
||||
).fontSize(15),
|
||||
],
|
||||
@@ -470,39 +466,38 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
isLabelVisible: (onlineCount.value ?? 0) > 1,
|
||||
label: Text('${(onlineCount.value ?? 0)}'),
|
||||
textStyle: GoogleFonts.robotoMono(fontSize: 10),
|
||||
backgroundColor:
|
||||
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey,
|
||||
backgroundColor: (onlineCount.value ?? 0) > 1
|
||||
? Colors.green
|
||||
: Colors.grey,
|
||||
textColor: Colors.white,
|
||||
offset: Offset(6, 14),
|
||||
child: SizedBox(
|
||||
height: 28,
|
||||
width: 28,
|
||||
child:
|
||||
(room!.type == 1 && room.picture?.id == null)
|
||||
? SplitAvatarWidget(
|
||||
filesId:
|
||||
getValidMembers(
|
||||
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),
|
||||
),
|
||||
child: (room!.type == 1 && room.picture == null)
|
||||
? SplitAvatarWidget(
|
||||
files: getValidMembers(
|
||||
room.members!,
|
||||
).map((e) => e.account.profile.picture).toList(),
|
||||
)
|
||||
: room.picture != null
|
||||
? ProfilePictureWidget(
|
||||
file: room.picture,
|
||||
fallbackIcon: Symbols.chat,
|
||||
)
|
||||
: CircleAvatar(
|
||||
child: Text(
|
||||
room.name![0].toUpperCase(),
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
(room.type == 1 && room.name == null)
|
||||
? getValidMembers(
|
||||
room.members!,
|
||||
).map((e) => e.account.nick).join(', ')
|
||||
room.members!,
|
||||
).map((e) => e.account.nick).join(', ')
|
||||
: room.name!,
|
||||
).fontSize(19),
|
||||
],
|
||||
@@ -531,11 +526,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
index: index,
|
||||
scrollController: scrollController,
|
||||
alignment: 0.5,
|
||||
duration:
|
||||
(estimatedDistance) => Duration(
|
||||
milliseconds:
|
||||
(estimatedDistance * 0.5).clamp(200, 800).toInt(),
|
||||
),
|
||||
duration: (estimatedDistance) => Duration(
|
||||
milliseconds: (estimatedDistance * 0.5).clamp(200, 800).toInt(),
|
||||
),
|
||||
curve: (estimatedDistance) => Curves.easeOutCubic,
|
||||
);
|
||||
|
||||
@@ -605,12 +598,11 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
final config = await showModalBottomSheet<AttachmentUploadConfig>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder:
|
||||
(context) => AttachmentUploaderSheet(
|
||||
ref: ref,
|
||||
attachments: attachments.value,
|
||||
index: index,
|
||||
),
|
||||
builder: (context) => AttachmentUploaderSheet(
|
||||
ref: ref,
|
||||
attachments: attachments.value,
|
||||
index: index,
|
||||
),
|
||||
);
|
||||
if (config == null) return;
|
||||
|
||||
@@ -621,22 +613,20 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
'chat-upload': {index: 0},
|
||||
};
|
||||
|
||||
final cloudFile =
|
||||
await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: attachment,
|
||||
poolId: config.poolId,
|
||||
mode:
|
||||
attachment.type == UniversalFileType.file
|
||||
? FileUploadMode.generic
|
||||
: FileUploadMode.mediaSafe,
|
||||
onProgress: (progress, _) {
|
||||
attachmentProgress.value = {
|
||||
...attachmentProgress.value,
|
||||
'chat-upload': {index: progress ?? 0.0},
|
||||
};
|
||||
},
|
||||
).future;
|
||||
final cloudFile = await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: attachment,
|
||||
poolId: config.poolId,
|
||||
mode: attachment.type == UniversalFileType.file
|
||||
? FileUploadMode.generic
|
||||
: FileUploadMode.mediaSafe,
|
||||
onProgress: (progress, _) {
|
||||
attachmentProgress.value = {
|
||||
...attachmentProgress.value,
|
||||
'chat-upload': {index: progress ?? 0.0},
|
||||
};
|
||||
},
|
||||
).future;
|
||||
|
||||
if (cloudFile == null) {
|
||||
throw ArgumentError('Failed to upload the file...');
|
||||
@@ -662,12 +652,12 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
curve: Curves.easeOut,
|
||||
tween: EdgeInsetsTween(
|
||||
begin: EdgeInsets.only(
|
||||
top: MediaQuery.of(context).padding.top,
|
||||
bottom: MediaQuery.of(context).padding.bottom + 8 + height,
|
||||
top: mediaQuery.padding.top,
|
||||
bottom: mediaQuery.padding.bottom + 8 + height,
|
||||
),
|
||||
end: EdgeInsets.only(
|
||||
top: MediaQuery.of(context).padding.top,
|
||||
bottom: MediaQuery.of(context).padding.bottom + 8 + height,
|
||||
top: mediaQuery.padding.top,
|
||||
bottom: mediaQuery.padding.bottom + 8 + height,
|
||||
),
|
||||
),
|
||||
builder: (context, padding, child) {
|
||||
@@ -690,10 +680,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
extentEstimation: (_, _) => 40,
|
||||
itemBuilder: (context, index) {
|
||||
final message = messageList[index];
|
||||
final nextMessage =
|
||||
index < messageList.length - 1
|
||||
? messageList[index + 1]
|
||||
: null;
|
||||
final nextMessage = index < messageList.length - 1
|
||||
? messageList[index + 1]
|
||||
: null;
|
||||
final isLastInGroup =
|
||||
nextMessage == null ||
|
||||
nextMessage.senderId != message.senderId ||
|
||||
@@ -718,15 +707,14 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
toggleSelectionMode: toggleSelectionMode,
|
||||
toggleMessageSelection: toggleMessageSelection,
|
||||
onMessageAction: onMessageAction,
|
||||
onJump:
|
||||
(messageId) => scrollToMessage(
|
||||
messageId: messageId,
|
||||
messageList: messageList,
|
||||
messagesNotifier: messagesNotifier,
|
||||
listController: listController,
|
||||
scrollController: scrollController,
|
||||
ref: ref,
|
||||
),
|
||||
onJump: (messageId) => scrollToMessage(
|
||||
messageId: messageId,
|
||||
messageList: messageList,
|
||||
messagesNotifier: messagesNotifier,
|
||||
listController: listController,
|
||||
scrollController: scrollController,
|
||||
ref: ref,
|
||||
),
|
||||
attachmentProgress: attachmentProgress.value,
|
||||
disableAnimation: settings.disableAnimation,
|
||||
roomOpenTime: roomOpenTime,
|
||||
@@ -744,17 +732,14 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
automaticallyImplyLeading: false,
|
||||
toolbarHeight: compactHeader ? null : 74,
|
||||
title: chatRoom.when(
|
||||
data:
|
||||
(room) =>
|
||||
compactHeader
|
||||
? compactHeaderWidget(room)
|
||||
: comfortHeaderWidget(room),
|
||||
data: (room) => compactHeader
|
||||
? compactHeaderWidget(room)
|
||||
: comfortHeaderWidget(room),
|
||||
loading: () => const Text('Loading...'),
|
||||
error:
|
||||
(err, _) => ResponseErrorWidget(
|
||||
error: err,
|
||||
onRetry: () => messagesNotifier.loadInitial(),
|
||||
),
|
||||
error: (err, _) => ResponseErrorWidget(
|
||||
error: err,
|
||||
onRetry: () => messagesNotifier.loadInitial(),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
chatRoom.when(
|
||||
@@ -787,13 +772,11 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
index: index,
|
||||
scrollController: scrollController,
|
||||
alignment: 0.5,
|
||||
duration:
|
||||
(estimatedDistance) => Duration(
|
||||
milliseconds:
|
||||
(estimatedDistance * 0.5)
|
||||
.clamp(200, 800)
|
||||
.toInt(),
|
||||
),
|
||||
duration: (estimatedDistance) => Duration(
|
||||
milliseconds: (estimatedDistance * 0.5)
|
||||
.clamp(200, 800)
|
||||
.toInt(),
|
||||
),
|
||||
curve: (estimatedDistance) => Curves.easeOutCubic,
|
||||
);
|
||||
} catch (e) {
|
||||
@@ -819,38 +802,35 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
duration: const Duration(milliseconds: 300),
|
||||
switchInCurve: Curves.easeOutCubic,
|
||||
switchOutCurve: Curves.easeInCubic,
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> animation,
|
||||
) {
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0, 0.05),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: FadeTransition(opacity: animation, child: child),
|
||||
);
|
||||
},
|
||||
transitionBuilder:
|
||||
(Widget child, Animation<double> animation) {
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0, 0.05),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: FadeTransition(
|
||||
opacity: animation,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: messages.when(
|
||||
data:
|
||||
(messageList) =>
|
||||
messageList.isEmpty
|
||||
? Center(
|
||||
key: const ValueKey('empty-messages'),
|
||||
child: Text('No messages yet'.tr()),
|
||||
)
|
||||
: chatMessageListWidget(messageList),
|
||||
loading:
|
||||
() => const Center(
|
||||
key: ValueKey('loading-messages'),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
error:
|
||||
(error, _) => ResponseErrorWidget(
|
||||
key: const ValueKey('error-messages'),
|
||||
error: error,
|
||||
onRetry: () => messagesNotifier.loadInitial(),
|
||||
),
|
||||
data: (messageList) => messageList.isEmpty
|
||||
? Center(
|
||||
key: const ValueKey('empty-messages'),
|
||||
child: Text('No messages yet'.tr()),
|
||||
)
|
||||
: chatMessageListWidget(messageList),
|
||||
loading: () => const Center(
|
||||
key: ValueKey('loading-messages'),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
error: (error, _) => ResponseErrorWidget(
|
||||
key: const ValueKey('error-messages'),
|
||||
error: error,
|
||||
onRetry: () => messagesNotifier.loadInitial(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -862,10 +842,8 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
right: 0,
|
||||
top: 0,
|
||||
child: chatRoom.when(
|
||||
data:
|
||||
(data) => CallOverlayBar(
|
||||
room: data!,
|
||||
).padding(horizontal: 8, top: 12),
|
||||
data: (data) =>
|
||||
CallOverlayBar(room: data!).padding(horizontal: 8, top: 12),
|
||||
error: (_, _) => const SizedBox.shrink(),
|
||||
loading: () => const SizedBox.shrink(),
|
||||
),
|
||||
@@ -875,7 +853,12 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
top: 8,
|
||||
right: 16,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8 + mediaQuery.padding.bottom,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(
|
||||
context,
|
||||
@@ -903,111 +886,100 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
if (!isSelectionMode.value)
|
||||
AnimatedBuilder(
|
||||
animation: bottomGradientNotifier.value,
|
||||
builder:
|
||||
(context, child) => Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Opacity(
|
||||
opacity: bottomGradientNotifier.value.value,
|
||||
child: Container(
|
||||
height: math.min(
|
||||
MediaQuery.of(context).size.height * 0.1,
|
||||
128,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
colors: [
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer.withOpacity(0.8),
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer.withOpacity(0.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
builder: (context, child) => Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Opacity(
|
||||
opacity: bottomGradientNotifier.value.value,
|
||||
child: Container(
|
||||
height: math.min(mediaQuery.size.height * 0.1, 128),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
colors: [
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer.withOpacity(0.8),
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer.withOpacity(0.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Chat Input positioned above gradient (higher z-index)
|
||||
if (!isSelectionMode.value)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0, // At the very bottom, above gradient
|
||||
bottom: mediaQuery
|
||||
.padding
|
||||
.bottom, // At the very bottom, above gradient
|
||||
child: chatRoom.when(
|
||||
data:
|
||||
(room) => Column(
|
||||
key: inputKey,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ChatInput(
|
||||
messageController: messageController,
|
||||
chatRoom: room!,
|
||||
onSend: sendMessage,
|
||||
onClear: () {
|
||||
if (messageEditingTo.value != null) {
|
||||
attachments.value.clear();
|
||||
messageController.clear();
|
||||
}
|
||||
messageEditingTo.value = null;
|
||||
messageReplyingTo.value = null;
|
||||
messageForwardingTo.value = null;
|
||||
selectedPoll.value = null;
|
||||
selectedFund.value = null;
|
||||
},
|
||||
messageEditingTo: messageEditingTo.value,
|
||||
messageReplyingTo: messageReplyingTo.value,
|
||||
messageForwardingTo: messageForwardingTo.value,
|
||||
selectedPoll: selectedPoll.value,
|
||||
onPollSelected: (poll) => selectedPoll.value = poll,
|
||||
selectedFund: selectedFund.value,
|
||||
onFundSelected: (fund) => selectedFund.value = fund,
|
||||
onPickFile: (bool isPhoto) {
|
||||
if (isPhoto) {
|
||||
pickPhotoMedia();
|
||||
} else {
|
||||
pickVideoMedia();
|
||||
}
|
||||
},
|
||||
onPickAudio: pickAudioMedia,
|
||||
onPickGeneralFile: pickGeneralFile,
|
||||
onLinkAttachment: linkAttachment,
|
||||
attachments: attachments.value,
|
||||
onUploadAttachment: uploadAttachment,
|
||||
onDeleteAttachment: (index) async {
|
||||
final attachment = attachments.value[index];
|
||||
if (attachment.isOnCloud && !attachment.isLink) {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.delete(
|
||||
'/drive/files/${attachment.data.id}',
|
||||
);
|
||||
}
|
||||
final clone = List.of(attachments.value);
|
||||
clone.removeAt(index);
|
||||
attachments.value = clone;
|
||||
},
|
||||
onMoveAttachment: (idx, delta) {
|
||||
if (idx + delta < 0 ||
|
||||
idx + delta >= attachments.value.length) {
|
||||
return;
|
||||
}
|
||||
final clone = List.of(attachments.value);
|
||||
clone.insert(idx + delta, clone.removeAt(idx));
|
||||
attachments.value = clone;
|
||||
},
|
||||
onAttachmentsChanged: (newAttachments) {
|
||||
attachments.value = newAttachments;
|
||||
},
|
||||
attachmentProgress: attachmentProgress.value,
|
||||
),
|
||||
Gap(MediaQuery.of(context).padding.bottom),
|
||||
],
|
||||
),
|
||||
data: (room) => ChatInput(
|
||||
key: inputKey,
|
||||
messageController: messageController,
|
||||
chatRoom: room!,
|
||||
onSend: sendMessage,
|
||||
onClear: () {
|
||||
if (messageEditingTo.value != null) {
|
||||
attachments.value.clear();
|
||||
messageController.clear();
|
||||
}
|
||||
messageEditingTo.value = null;
|
||||
messageReplyingTo.value = null;
|
||||
messageForwardingTo.value = null;
|
||||
selectedPoll.value = null;
|
||||
selectedFund.value = null;
|
||||
},
|
||||
messageEditingTo: messageEditingTo.value,
|
||||
messageReplyingTo: messageReplyingTo.value,
|
||||
messageForwardingTo: messageForwardingTo.value,
|
||||
selectedPoll: selectedPoll.value,
|
||||
onPollSelected: (poll) => selectedPoll.value = poll,
|
||||
selectedFund: selectedFund.value,
|
||||
onFundSelected: (fund) => selectedFund.value = fund,
|
||||
onPickFile: (bool isPhoto) {
|
||||
if (isPhoto) {
|
||||
pickPhotoMedia();
|
||||
} else {
|
||||
pickVideoMedia();
|
||||
}
|
||||
},
|
||||
onPickAudio: pickAudioMedia,
|
||||
onPickGeneralFile: pickGeneralFile,
|
||||
onLinkAttachment: linkAttachment,
|
||||
attachments: attachments.value,
|
||||
onUploadAttachment: uploadAttachment,
|
||||
onDeleteAttachment: (index) async {
|
||||
final attachment = attachments.value[index];
|
||||
if (attachment.isOnCloud && !attachment.isLink) {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.delete('/drive/files/${attachment.data.id}');
|
||||
}
|
||||
final clone = List.of(attachments.value);
|
||||
clone.removeAt(index);
|
||||
attachments.value = clone;
|
||||
},
|
||||
onMoveAttachment: (idx, delta) {
|
||||
if (idx + delta < 0 ||
|
||||
idx + delta >= attachments.value.length) {
|
||||
return;
|
||||
}
|
||||
final clone = List.of(attachments.value);
|
||||
clone.insert(idx + delta, clone.removeAt(idx));
|
||||
attachments.value = clone;
|
||||
},
|
||||
onAttachmentsChanged: (newAttachments) {
|
||||
attachments.value = newAttachments;
|
||||
},
|
||||
attachmentProgress: attachmentProgress.value,
|
||||
),
|
||||
error: (_, _) => const SizedBox.shrink(),
|
||||
loading: () => const SizedBox.shrink(),
|
||||
),
|
||||
@@ -1024,7 +996,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
left: 16,
|
||||
right: 16,
|
||||
top: 8,
|
||||
bottom: MediaQuery.of(context).padding.bottom + 8,
|
||||
bottom: mediaQuery.padding.bottom + 8,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
|
||||
@@ -67,7 +67,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.patch(
|
||||
'/sphere/chat/$id/members/me/notify',
|
||||
'/messager/chat/$id/members/me/notify',
|
||||
data: {'notify_level': level},
|
||||
);
|
||||
ref.invalidate(chatRoomIdentityProvider(id));
|
||||
@@ -85,7 +85,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.patch(
|
||||
'/sphere/chat/$id/members/me/notify',
|
||||
'/messager/chat/$id/members/me/notify',
|
||||
data: {'break_until': until.toUtc().toIso8601String()},
|
||||
);
|
||||
ref.invalidate(chatRoomIdentityProvider(id));
|
||||
@@ -279,9 +279,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
leading: PageBackButton(shadows: [iconShadow]),
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
background:
|
||||
(currentRoom!.type == 1 &&
|
||||
currentRoom.background?.id != null)
|
||||
? CloudImageWidget(fileId: currentRoom.background!.id)
|
||||
(currentRoom!.type == 1 && currentRoom.background != null)
|
||||
? CloudImageWidget(file: currentRoom.background!)
|
||||
: (currentRoom.type == 1 &&
|
||||
currentRoom.members!.length == 1 &&
|
||||
currentRoom
|
||||
@@ -293,17 +292,16 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
?.id !=
|
||||
null)
|
||||
? CloudImageWidget(
|
||||
fileId: currentRoom
|
||||
file: currentRoom
|
||||
.members!
|
||||
.first
|
||||
.account
|
||||
.profile
|
||||
.background!
|
||||
.id,
|
||||
.background!,
|
||||
)
|
||||
: currentRoom.background?.id != null
|
||||
: currentRoom.background != null
|
||||
? CloudImageWidget(
|
||||
fileId: currentRoom.background!.id,
|
||||
file: currentRoom.background!,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Container(
|
||||
@@ -529,7 +527,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
||||
).then((confirm) async {
|
||||
if (confirm) {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.delete('/sphere/chat/$id');
|
||||
await client.delete('/messager/chat/$id');
|
||||
ref.invalidate(chatRoomJoinedProvider);
|
||||
if (context.mounted) {
|
||||
context.pop();
|
||||
@@ -560,7 +558,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
||||
).then((confirm) async {
|
||||
if (confirm) {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.delete('/sphere/chat/$id/members/me');
|
||||
await client.delete('/messager/chat/$id/members/me');
|
||||
ref.invalidate(chatRoomJoinedProvider);
|
||||
if (context.mounted) {
|
||||
context.pop();
|
||||
@@ -588,7 +586,8 @@ final chatMemberListProvider = AsyncNotifierProvider.autoDispose.family(
|
||||
ChatMemberListNotifier.new,
|
||||
);
|
||||
|
||||
class ChatMemberListNotifier extends AsyncNotifier<List<SnChatMember>>
|
||||
class ChatMemberListNotifier
|
||||
extends AsyncNotifier<PaginationState<SnChatMember>>
|
||||
with AsyncPaginationController<SnChatMember> {
|
||||
static const pageSize = 20;
|
||||
|
||||
@@ -599,7 +598,7 @@ class ChatMemberListNotifier extends AsyncNotifier<List<SnChatMember>>
|
||||
Future<List<SnChatMember>> fetch() async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final response = await apiClient.get(
|
||||
'/sphere/chat/$arg/members',
|
||||
'/messager/chat/$arg/members',
|
||||
queryParameters: {
|
||||
'offset': fetchedCount.toString(),
|
||||
'take': pageSize,
|
||||
@@ -623,7 +622,8 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final memberNotifier = ref.read(chatMemberListProvider(roomId).notifier);
|
||||
final memberState = ref.watch(chatMemberListProvider(roomId));
|
||||
final memberNotifier = ref.watch(chatMemberListProvider(roomId).notifier);
|
||||
|
||||
final roomIdentity = ref.watch(chatRoomIdentityProvider(roomId));
|
||||
final chatRoom = ref.watch(chatRoomProvider(roomId));
|
||||
@@ -643,7 +643,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
||||
try {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
await apiClient.post(
|
||||
'/sphere/chat/invites/$roomId',
|
||||
'/messager/chat/invites/$roomId',
|
||||
data: {'related_user_id': result.id, 'role': 0},
|
||||
);
|
||||
memberNotifier.refresh();
|
||||
@@ -663,7 +663,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'members'.plural(memberNotifier.totalCount ?? 0),
|
||||
'members'.plural(memberState.value?.totalCount ?? 0),
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: -0.5,
|
||||
@@ -700,7 +700,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
||||
leading: AccountPfcGestureDetector(
|
||||
uname: member.account.name,
|
||||
child: ProfilePictureWidget(
|
||||
fileId: member.account.profile.picture?.id,
|
||||
file: member.account.profile.picture,
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
@@ -733,7 +733,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
||||
try {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
await apiClient.delete(
|
||||
'/sphere/chat/$roomId/members/${member.accountId}',
|
||||
'/messager/chat/$roomId/members/${member.accountId}',
|
||||
);
|
||||
// Refresh both providers
|
||||
memberNotifier.refresh();
|
||||
|
||||
@@ -10,12 +10,12 @@ part of 'room_detail.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(totalMessagesCount)
|
||||
const totalMessagesCountProvider = TotalMessagesCountFamily._();
|
||||
final totalMessagesCountProvider = TotalMessagesCountFamily._();
|
||||
|
||||
final class TotalMessagesCountProvider
|
||||
extends $FunctionalProvider<AsyncValue<int>, int, FutureOr<int>>
|
||||
with $FutureModifier<int>, $FutureProvider<int> {
|
||||
const TotalMessagesCountProvider._({
|
||||
TotalMessagesCountProvider._({
|
||||
required TotalMessagesCountFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -63,7 +63,7 @@ String _$totalMessagesCountHash() =>
|
||||
|
||||
final class TotalMessagesCountFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<int>, String> {
|
||||
const TotalMessagesCountFamily._()
|
||||
TotalMessagesCountFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'totalMessagesCountProvider',
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/activitypub.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/models/publisher.dart';
|
||||
import 'package:island/models/heatmap.dart';
|
||||
@@ -15,6 +16,7 @@ import 'package:island/screens/creators/publishers_form.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/utils/text.dart';
|
||||
import 'package:island/widgets/account/account_picker.dart';
|
||||
import 'package:island/widgets/activitypub/actor_profile.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
@@ -78,16 +80,43 @@ Future<List<SnPublisherMember>> publisherInvites(Ref ref) async {
|
||||
.toList();
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<SnActorStatusResponse> publisherActorStatus(
|
||||
Ref ref,
|
||||
String? publisherName,
|
||||
) async {
|
||||
if (publisherName == null) throw Exception('Publisher name is required');
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final response = await apiClient.get(
|
||||
'/sphere/publishers/$publisherName/fediverse',
|
||||
);
|
||||
return SnActorStatusResponse.fromJson(response.data);
|
||||
}
|
||||
|
||||
final publisherMemberListNotifierProvider = AsyncNotifierProvider.family
|
||||
.autoDispose(PublisherMemberListNotifier.new);
|
||||
|
||||
class PublisherMemberListNotifier extends AsyncNotifier<List<SnPublisherMember>>
|
||||
class PublisherMemberListNotifier
|
||||
extends AsyncNotifier<PaginationState<SnPublisherMember>>
|
||||
with AsyncPaginationController<SnPublisherMember> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
final String arg;
|
||||
PublisherMemberListNotifier(this.arg);
|
||||
|
||||
@override
|
||||
FutureOr<PaginationState<SnPublisherMember>> build() async {
|
||||
final items = await fetch();
|
||||
return PaginationState(
|
||||
items: items,
|
||||
isLoading: false,
|
||||
isReloading: false,
|
||||
totalCount: totalCount,
|
||||
hasMore: hasMore,
|
||||
cursor: cursor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SnPublisherMember>> fetch() async {
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
@@ -126,7 +155,7 @@ class PublisherSelector extends StatelessWidget {
|
||||
if (isReadOnly || currentPublisher == null) {
|
||||
return ProfilePictureWidget(
|
||||
radius: 16,
|
||||
fileId: currentPublisher?.picture?.id,
|
||||
file: currentPublisher?.picture,
|
||||
).center().padding(right: 8);
|
||||
}
|
||||
|
||||
@@ -150,7 +179,7 @@ class PublisherSelector extends StatelessWidget {
|
||||
.map(
|
||||
(e) => ProfilePictureWidget(
|
||||
radius: 16,
|
||||
fileId: e.value?.picture?.id,
|
||||
file: e.value?.picture,
|
||||
).center().padding(right: 8),
|
||||
)
|
||||
.toList();
|
||||
@@ -326,10 +355,7 @@ class CreatorHubScreen extends HookConsumerWidget {
|
||||
value: item,
|
||||
child: ListTile(
|
||||
minTileHeight: 48,
|
||||
leading: ProfilePictureWidget(
|
||||
radius: 16,
|
||||
fileId: item.picture?.id,
|
||||
),
|
||||
leading: ProfilePictureWidget(radius: 16, file: item.picture),
|
||||
title: Text(item.nick),
|
||||
subtitle: Text('@${item.name}'),
|
||||
trailing: currentPublisher.value?.id == item.id
|
||||
@@ -501,6 +527,24 @@ class CreatorHubScreen extends HookConsumerWidget {
|
||||
leading: const Icon(Symbols.edit),
|
||||
onTap: updatePublisher,
|
||||
),
|
||||
ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
minTileHeight: 48,
|
||||
title: Text('publisherFediverse').tr(),
|
||||
trailing: Icon(Symbols.chevron_right),
|
||||
leading: const Icon(Symbols.public),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (context) => _PublisherFediverseSheet(
|
||||
publisherUname: currentPublisher.value!.name,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
@@ -842,7 +886,7 @@ class _PublisherMemberListSheet extends HookConsumerWidget {
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 16, right: 12),
|
||||
leading: ProfilePictureWidget(
|
||||
fileId: member.account!.profile.picture?.id,
|
||||
file: member.account!.profile.picture,
|
||||
),
|
||||
title: Row(
|
||||
spacing: 6,
|
||||
@@ -1090,7 +1134,7 @@ class _PublisherInviteSheet extends HookConsumerWidget {
|
||||
final invite = items[index];
|
||||
return ListTile(
|
||||
leading: ProfilePictureWidget(
|
||||
fileId: invite.publisher!.picture?.id,
|
||||
file: invite.publisher!.picture,
|
||||
fallbackIcon: Symbols.group,
|
||||
),
|
||||
title: Text(invite.publisher!.nick),
|
||||
@@ -1126,3 +1170,152 @@ class _PublisherInviteSheet extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PublisherFediverseSheet extends HookConsumerWidget {
|
||||
final String publisherUname;
|
||||
|
||||
const _PublisherFediverseSheet({required this.publisherUname});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final actorStatus = ref.watch(publisherActorStatusProvider(publisherUname));
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final isLoading = useState(false);
|
||||
|
||||
Future<void> toggleActor() async {
|
||||
final currentStatus = actorStatus.value;
|
||||
if (currentStatus == null) return;
|
||||
|
||||
final confirm = await showConfirmAlert(
|
||||
currentStatus.enabled
|
||||
? 'publisherFediverseDisableConfirm'.tr()
|
||||
: 'publisherFediverseEnableConfirm'.tr(),
|
||||
currentStatus.enabled
|
||||
? 'publisherFediverseDisabled'.tr()
|
||||
: 'publisherFediverseEnabled'.tr(),
|
||||
isDanger: !currentStatus.enabled,
|
||||
);
|
||||
if (confirm != true) return;
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
if (currentStatus.enabled) {
|
||||
await apiClient.delete(
|
||||
'/sphere/publishers/$publisherUname/fediverse',
|
||||
);
|
||||
} else {
|
||||
await apiClient.post('/sphere/publishers/$publisherUname/fediverse');
|
||||
}
|
||||
ref.invalidate(publisherActorStatusProvider(publisherUname));
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return SheetScaffold(
|
||||
titleText: 'publisherFediverse'.tr(),
|
||||
child: actorStatus.when(
|
||||
data: (status) => SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Card.outlined(
|
||||
child: SwitchListTile(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
value: status.enabled,
|
||||
onChanged: isLoading.value ? null : (_) => toggleActor(),
|
||||
title: Text(
|
||||
status.enabled
|
||||
? 'publisherFediverseEnabled'.tr()
|
||||
: 'publisherFediverseDisabled'.tr(),
|
||||
),
|
||||
subtitle: Text(
|
||||
status.enabled
|
||||
? 'publisherFediverseDisableHint'.tr()
|
||||
: 'publisherFediverseEnableHint'.tr(),
|
||||
),
|
||||
secondary: isLoading.value
|
||||
? const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: Icon(
|
||||
status.enabled
|
||||
? Icons.check_circle
|
||||
: Icons.circle_outlined,
|
||||
color: status.enabled ? Colors.green : Colors.grey,
|
||||
),
|
||||
),
|
||||
).padding(horizontal: 16),
|
||||
if (status.enabled) ...[
|
||||
if (status.actor != null) ...[
|
||||
ListTile(
|
||||
leading: ActorPictureWidget(
|
||||
actor: status.actor!,
|
||||
radius: 24,
|
||||
),
|
||||
title: Text(
|
||||
status.actor!.displayName ??
|
||||
status.actor!.username ??
|
||||
'unknown'.tr(),
|
||||
),
|
||||
subtitle: Text(
|
||||
'@${status.actor!.username}@${status.actor!.instance.domain}',
|
||||
),
|
||||
isThreeLine: true,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 28),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.link),
|
||||
title: Text('publisherFediverseActorUri').tr(),
|
||||
subtitle: Text(status.actorUri ?? 'N/A'),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
),
|
||||
],
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.group),
|
||||
title: Text('publisherFediverseFollowerCount').tr(),
|
||||
subtitle: Text(
|
||||
status.followerCount > 0
|
||||
? status.followerCount.toString()
|
||||
: 'publisherFediverseNoFollowers'.tr(),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
),
|
||||
],
|
||||
ExpansionTile(
|
||||
leading: const Icon(Symbols.info),
|
||||
title: Text('publisherFediverseWhatIs').tr(),
|
||||
tilePadding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16,
|
||||
horizontal: 32,
|
||||
),
|
||||
child: Text('publisherFediverseAbout').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, _) => ResponseErrorWidget(
|
||||
error: error,
|
||||
onRetry: () =>
|
||||
ref.invalidate(publisherActorStatusProvider(publisherUname)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'hub.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(publisherStats)
|
||||
const publisherStatsProvider = PublisherStatsFamily._();
|
||||
final publisherStatsProvider = PublisherStatsFamily._();
|
||||
|
||||
final class PublisherStatsProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class PublisherStatsProvider
|
||||
with
|
||||
$FutureModifier<SnPublisherStats?>,
|
||||
$FutureProvider<SnPublisherStats?> {
|
||||
const PublisherStatsProvider._({
|
||||
PublisherStatsProvider._({
|
||||
required PublisherStatsFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -70,7 +70,7 @@ String _$publisherStatsHash() => r'eea4ed98bf165cc785874f83b912bb7e23d1f7bc';
|
||||
|
||||
final class PublisherStatsFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnPublisherStats?>, String?> {
|
||||
const PublisherStatsFamily._()
|
||||
PublisherStatsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publisherStatsProvider',
|
||||
@@ -87,7 +87,7 @@ final class PublisherStatsFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(publisherHeatmap)
|
||||
const publisherHeatmapProvider = PublisherHeatmapFamily._();
|
||||
final publisherHeatmapProvider = PublisherHeatmapFamily._();
|
||||
|
||||
final class PublisherHeatmapProvider
|
||||
extends
|
||||
@@ -97,7 +97,7 @@ final class PublisherHeatmapProvider
|
||||
FutureOr<SnHeatmap?>
|
||||
>
|
||||
with $FutureModifier<SnHeatmap?>, $FutureProvider<SnHeatmap?> {
|
||||
const PublisherHeatmapProvider._({
|
||||
PublisherHeatmapProvider._({
|
||||
required PublisherHeatmapFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -144,7 +144,7 @@ String _$publisherHeatmapHash() => r'5f70c55e14629ec8628445a317888e02fccd9af2';
|
||||
|
||||
final class PublisherHeatmapFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnHeatmap?>, String?> {
|
||||
const PublisherHeatmapFamily._()
|
||||
PublisherHeatmapFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publisherHeatmapProvider',
|
||||
@@ -161,7 +161,7 @@ final class PublisherHeatmapFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(publisherIdentity)
|
||||
const publisherIdentityProvider = PublisherIdentityFamily._();
|
||||
final publisherIdentityProvider = PublisherIdentityFamily._();
|
||||
|
||||
final class PublisherIdentityProvider
|
||||
extends
|
||||
@@ -173,7 +173,7 @@ final class PublisherIdentityProvider
|
||||
with
|
||||
$FutureModifier<SnPublisherMember?>,
|
||||
$FutureProvider<SnPublisherMember?> {
|
||||
const PublisherIdentityProvider._({
|
||||
PublisherIdentityProvider._({
|
||||
required PublisherIdentityFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -221,7 +221,7 @@ String _$publisherIdentityHash() => r'299372f25fa4b2bf8e11a8ba2d645100fc38e76f';
|
||||
|
||||
final class PublisherIdentityFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnPublisherMember?>, String> {
|
||||
const PublisherIdentityFamily._()
|
||||
PublisherIdentityFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publisherIdentityProvider',
|
||||
@@ -238,7 +238,7 @@ final class PublisherIdentityFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(publisherFeatures)
|
||||
const publisherFeaturesProvider = PublisherFeaturesFamily._();
|
||||
final publisherFeaturesProvider = PublisherFeaturesFamily._();
|
||||
|
||||
final class PublisherFeaturesProvider
|
||||
extends
|
||||
@@ -250,7 +250,7 @@ final class PublisherFeaturesProvider
|
||||
with
|
||||
$FutureModifier<Map<String, bool>>,
|
||||
$FutureProvider<Map<String, bool>> {
|
||||
const PublisherFeaturesProvider._({
|
||||
PublisherFeaturesProvider._({
|
||||
required PublisherFeaturesFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -298,7 +298,7 @@ String _$publisherFeaturesHash() => r'08bace2d9a3da227ecec0cbf8709e55ee0646ca2';
|
||||
|
||||
final class PublisherFeaturesFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<Map<String, bool>>, String?> {
|
||||
const PublisherFeaturesFamily._()
|
||||
PublisherFeaturesFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publisherFeaturesProvider',
|
||||
@@ -315,7 +315,7 @@ final class PublisherFeaturesFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(publisherInvites)
|
||||
const publisherInvitesProvider = PublisherInvitesProvider._();
|
||||
final publisherInvitesProvider = PublisherInvitesProvider._();
|
||||
|
||||
final class PublisherInvitesProvider
|
||||
extends
|
||||
@@ -327,7 +327,7 @@ final class PublisherInvitesProvider
|
||||
with
|
||||
$FutureModifier<List<SnPublisherMember>>,
|
||||
$FutureProvider<List<SnPublisherMember>> {
|
||||
const PublisherInvitesProvider._()
|
||||
PublisherInvitesProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -354,3 +354,81 @@ final class PublisherInvitesProvider
|
||||
}
|
||||
|
||||
String _$publisherInvitesHash() => r'93aafc2f02af0a7a055ec1770b3999363dfaabdc';
|
||||
|
||||
@ProviderFor(publisherActorStatus)
|
||||
final publisherActorStatusProvider = PublisherActorStatusFamily._();
|
||||
|
||||
final class PublisherActorStatusProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<SnActorStatusResponse>,
|
||||
SnActorStatusResponse,
|
||||
FutureOr<SnActorStatusResponse>
|
||||
>
|
||||
with
|
||||
$FutureModifier<SnActorStatusResponse>,
|
||||
$FutureProvider<SnActorStatusResponse> {
|
||||
PublisherActorStatusProvider._({
|
||||
required PublisherActorStatusFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'publisherActorStatusProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$publisherActorStatusHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'publisherActorStatusProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<SnActorStatusResponse> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<SnActorStatusResponse> create(Ref ref) {
|
||||
final argument = this.argument as String?;
|
||||
return publisherActorStatus(ref, argument);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is PublisherActorStatusProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$publisherActorStatusHash() =>
|
||||
r'406117cb99b2aef236945ef0ef59e857d8835029';
|
||||
|
||||
final class PublisherActorStatusFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnActorStatusResponse>, String?> {
|
||||
PublisherActorStatusFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publisherActorStatusProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
PublisherActorStatusProvider call(String? publisherName) =>
|
||||
PublisherActorStatusProvider._(argument: publisherName, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'publisherActorStatusProvider';
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ final pollListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
|
||||
PollListNotifier.new,
|
||||
);
|
||||
|
||||
class PollListNotifier extends AsyncNotifier<List<SnPollWithStats>>
|
||||
class PollListNotifier extends AsyncNotifier<PaginationState<SnPollWithStats>>
|
||||
with AsyncPaginationController<SnPollWithStats> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'poll_list.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(pollWithStats)
|
||||
const pollWithStatsProvider = PollWithStatsFamily._();
|
||||
final pollWithStatsProvider = PollWithStatsFamily._();
|
||||
|
||||
final class PollWithStatsProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class PollWithStatsProvider
|
||||
FutureOr<SnPollWithStats>
|
||||
>
|
||||
with $FutureModifier<SnPollWithStats>, $FutureProvider<SnPollWithStats> {
|
||||
const PollWithStatsProvider._({
|
||||
PollWithStatsProvider._({
|
||||
required PollWithStatsFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -68,7 +68,7 @@ String _$pollWithStatsHash() => r'6bb910046ce1e09368f9922dbec52fdc2cc86740';
|
||||
|
||||
final class PollWithStatsFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnPollWithStats>, String> {
|
||||
const PollWithStatsFamily._()
|
||||
PollWithStatsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'pollWithStatsProvider',
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'publishers_form.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(publishersManaged)
|
||||
const publishersManagedProvider = PublishersManagedProvider._();
|
||||
final publishersManagedProvider = PublishersManagedProvider._();
|
||||
|
||||
final class PublishersManagedProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class PublishersManagedProvider
|
||||
with
|
||||
$FutureModifier<List<SnPublisher>>,
|
||||
$FutureProvider<List<SnPublisher>> {
|
||||
const PublishersManagedProvider._()
|
||||
PublishersManagedProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -51,7 +51,7 @@ final class PublishersManagedProvider
|
||||
String _$publishersManagedHash() => r'ea83759fed9bd5119738b4d09f12b4476959e0a3';
|
||||
|
||||
@ProviderFor(publisherNullable)
|
||||
const publisherNullableProvider = PublisherNullableFamily._();
|
||||
final publisherNullableProvider = PublisherNullableFamily._();
|
||||
|
||||
final class PublisherNullableProvider
|
||||
extends
|
||||
@@ -61,7 +61,7 @@ final class PublisherNullableProvider
|
||||
FutureOr<SnPublisher?>
|
||||
>
|
||||
with $FutureModifier<SnPublisher?>, $FutureProvider<SnPublisher?> {
|
||||
const PublisherNullableProvider._({
|
||||
PublisherNullableProvider._({
|
||||
required PublisherNullableFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -109,7 +109,7 @@ String _$publisherNullableHash() => r'49b28083a2f351c5e5cde0b1a97f6c7503969041';
|
||||
|
||||
final class PublisherNullableFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnPublisher?>, String?> {
|
||||
const PublisherNullableFamily._()
|
||||
PublisherNullableFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publisherNullableProvider',
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'site_detail.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(publicationSiteDetail)
|
||||
const publicationSiteDetailProvider = PublicationSiteDetailFamily._();
|
||||
final publicationSiteDetailProvider = PublicationSiteDetailFamily._();
|
||||
|
||||
final class PublicationSiteDetailProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class PublicationSiteDetailProvider
|
||||
with
|
||||
$FutureModifier<SnPublicationSite>,
|
||||
$FutureProvider<SnPublicationSite> {
|
||||
const PublicationSiteDetailProvider._({
|
||||
PublicationSiteDetailProvider._({
|
||||
required PublicationSiteDetailFamily super.from,
|
||||
required (String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -75,7 +75,7 @@ final class PublicationSiteDetailFamily extends $Family
|
||||
FutureOr<SnPublicationSite>,
|
||||
(String, String)
|
||||
> {
|
||||
const PublicationSiteDetailFamily._()
|
||||
PublicationSiteDetailFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publicationSiteDetailProvider',
|
||||
|
||||
@@ -18,7 +18,7 @@ final siteListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
|
||||
SiteListNotifier.new,
|
||||
);
|
||||
|
||||
class SiteListNotifier extends AsyncNotifier<List<SnPublicationSite>>
|
||||
class SiteListNotifier extends AsyncNotifier<PaginationState<SnPublicationSite>>
|
||||
with AsyncPaginationController<SnPublicationSite> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
|
||||
@@ -69,157 +69,141 @@ class StickerPackDetailContent extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return pack.when(
|
||||
data:
|
||||
(pack) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
data: (pack) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
Text(pack!.description),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text(pack!.description),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
const Icon(Symbols.folder, size: 16),
|
||||
Text(
|
||||
'${packContent.value?.length ?? 0}/24',
|
||||
style: GoogleFonts.robotoMono(),
|
||||
),
|
||||
],
|
||||
).opacity(0.85),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
const Icon(Symbols.sell, size: 16),
|
||||
Text(pack.prefix, style: GoogleFonts.robotoMono()),
|
||||
],
|
||||
).opacity(0.85),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
const Icon(Symbols.tag, size: 16),
|
||||
Flexible(
|
||||
child: SelectableText(
|
||||
pack.id,
|
||||
maxLines: 1,
|
||||
style: GoogleFonts.robotoMono(),
|
||||
),
|
||||
),
|
||||
],
|
||||
).opacity(0.85),
|
||||
const Icon(Symbols.folder, size: 16),
|
||||
Text(
|
||||
'${packContent.value?.length ?? 0}/24',
|
||||
style: GoogleFonts.robotoMono(),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 24, vertical: 24),
|
||||
const Divider(height: 1),
|
||||
Expanded(
|
||||
child: packContent.when(
|
||||
data:
|
||||
(stickers) => RefreshIndicator(
|
||||
onRefresh:
|
||||
() => ref.refresh(
|
||||
stickerPackContentProvider(id).future,
|
||||
),
|
||||
child: GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 20,
|
||||
),
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 80,
|
||||
mainAxisSpacing: 8,
|
||||
crossAxisSpacing: 8,
|
||||
),
|
||||
itemCount: stickers.length,
|
||||
itemBuilder: (context, index) {
|
||||
final sticker = stickers[index];
|
||||
return ContextMenuWidget(
|
||||
menuProvider: (_) {
|
||||
return Menu(
|
||||
children: [
|
||||
MenuAction(
|
||||
title: 'stickerCopyPlaceholder'.tr(),
|
||||
image: MenuImage.icon(Symbols.copy_all),
|
||||
callback: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text:
|
||||
':${pack.prefix}+${sticker.slug}:',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
MenuSeparator(),
|
||||
MenuAction(
|
||||
title: 'edit'.tr(),
|
||||
image: MenuImage.icon(Symbols.edit),
|
||||
callback: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder:
|
||||
(context) => SheetScaffold(
|
||||
titleText: 'editSticker'.tr(),
|
||||
child: StickerForm(
|
||||
packId: id,
|
||||
id: sticker.id,
|
||||
),
|
||||
),
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
ref.invalidate(
|
||||
stickerPackContentProvider(id),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
MenuAction(
|
||||
title: 'delete'.tr(),
|
||||
image: MenuImage.icon(Symbols.delete),
|
||||
callback: () {
|
||||
deleteSticker(sticker);
|
||||
},
|
||||
),
|
||||
],
|
||||
).opacity(0.85),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
const Icon(Symbols.sell, size: 16),
|
||||
Text(pack.prefix, style: GoogleFonts.robotoMono()),
|
||||
],
|
||||
).opacity(0.85),
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
const Icon(Symbols.tag, size: 16),
|
||||
Flexible(
|
||||
child: SelectableText(
|
||||
pack.id,
|
||||
maxLines: 1,
|
||||
style: GoogleFonts.robotoMono(),
|
||||
),
|
||||
),
|
||||
],
|
||||
).opacity(0.85),
|
||||
],
|
||||
).padding(horizontal: 24, vertical: 24),
|
||||
const Divider(height: 1),
|
||||
Expanded(
|
||||
child: packContent.when(
|
||||
data: (stickers) => RefreshIndicator(
|
||||
onRefresh: () =>
|
||||
ref.refresh(stickerPackContentProvider(id).future),
|
||||
child: GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 20,
|
||||
),
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 80,
|
||||
mainAxisSpacing: 8,
|
||||
crossAxisSpacing: 8,
|
||||
),
|
||||
itemCount: stickers.length,
|
||||
itemBuilder: (context, index) {
|
||||
final sticker = stickers[index];
|
||||
return ContextMenuWidget(
|
||||
menuProvider: (_) {
|
||||
return Menu(
|
||||
children: [
|
||||
MenuAction(
|
||||
title: 'stickerCopyPlaceholder'.tr(),
|
||||
image: MenuImage.icon(Symbols.copy_all),
|
||||
callback: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: ':${pack.prefix}+${sticker.slug}:',
|
||||
),
|
||||
);
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8),
|
||||
),
|
||||
MenuSeparator(),
|
||||
MenuAction(
|
||||
title: 'edit'.tr(),
|
||||
image: MenuImage.icon(Symbols.edit),
|
||||
callback: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => SheetScaffold(
|
||||
titleText: 'editSticker'.tr(),
|
||||
child: StickerForm(
|
||||
packId: id,
|
||||
id: sticker.id,
|
||||
),
|
||||
),
|
||||
child: CloudImageWidget(
|
||||
fileId: sticker.image.id,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
ref.invalidate(
|
||||
stickerPackContentProvider(id),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
MenuAction(
|
||||
title: 'delete'.tr(),
|
||||
image: MenuImage.icon(Symbols.delete),
|
||||
callback: () {
|
||||
deleteSticker(sticker);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
child: CloudImageWidget(
|
||||
file: sticker.image,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
error:
|
||||
(err, _) =>
|
||||
Text(
|
||||
'Error: $err',
|
||||
).textAlignment(TextAlign.center).center(),
|
||||
loading: () => const CircularProgressIndicator().center(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
error: (err, _) =>
|
||||
Text('Error: $err').textAlignment(TextAlign.center).center(),
|
||||
loading: () => const CircularProgressIndicator().center(),
|
||||
),
|
||||
),
|
||||
error:
|
||||
(err, _) =>
|
||||
Text('Error: $err').textAlignment(TextAlign.center).center(),
|
||||
],
|
||||
),
|
||||
error: (err, _) =>
|
||||
Text('Error: $err').textAlignment(TextAlign.center).center(),
|
||||
loading: () => const CircularProgressIndicator().center(),
|
||||
);
|
||||
}
|
||||
@@ -241,65 +225,60 @@ class StickerPackActionMenu extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return PopupMenuButton(
|
||||
icon: Icon(Icons.more_vert, shadows: [iconShadow]),
|
||||
itemBuilder:
|
||||
(context) => [
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder:
|
||||
(context) => SheetScaffold(
|
||||
titleText: 'editStickerPack'.tr(),
|
||||
child: StickerPackForm(
|
||||
pubName: pubName,
|
||||
packId: packId,
|
||||
),
|
||||
),
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
ref.invalidate(stickerPackProvider(packId));
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.edit,
|
||||
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||
),
|
||||
const Gap(12),
|
||||
const Text('editStickerPack').tr(),
|
||||
],
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => SheetScaffold(
|
||||
titleText: 'editStickerPack'.tr(),
|
||||
child: StickerPackForm(pubName: pubName, packId: packId),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.delete, color: Colors.red),
|
||||
const Gap(12),
|
||||
const Text(
|
||||
'deleteStickerPack',
|
||||
style: TextStyle(color: Colors.red),
|
||||
).tr(),
|
||||
],
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
ref.invalidate(stickerPackProvider(packId));
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.edit,
|
||||
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||
),
|
||||
onTap: () {
|
||||
showConfirmAlert(
|
||||
'deleteStickerPackHint'.tr(),
|
||||
'deleteStickerPack'.tr(),
|
||||
isDanger: true,
|
||||
).then((confirm) {
|
||||
if (confirm) {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
client.delete('/sphere/stickers/$packId');
|
||||
ref.invalidate(stickerPacksProvider);
|
||||
if (context.mounted) context.pop(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
const Gap(12),
|
||||
const Text('editStickerPack').tr(),
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.delete, color: Colors.red),
|
||||
const Gap(12),
|
||||
const Text(
|
||||
'deleteStickerPack',
|
||||
style: TextStyle(color: Colors.red),
|
||||
).tr(),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
showConfirmAlert(
|
||||
'deleteStickerPackHint'.tr(),
|
||||
'deleteStickerPack'.tr(),
|
||||
isDanger: true,
|
||||
).then((confirm) {
|
||||
if (confirm) {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
client.delete('/sphere/stickers/$packId');
|
||||
ref.invalidate(stickerPacksProvider);
|
||||
if (context.mounted) context.pop(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -372,10 +351,9 @@ class StickerForm extends HookConsumerWidget {
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
child:
|
||||
(image.value?.isEmpty ?? true)
|
||||
? const SizedBox.shrink()
|
||||
: CloudImageWidget(fileId: image.value!),
|
||||
child: (image.value?.isEmpty ?? true)
|
||||
? const SizedBox.shrink()
|
||||
: CloudImageWidget(fileId: image.value!),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -383,10 +361,8 @@ class StickerForm extends HookConsumerWidget {
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => CloudFilePicker(
|
||||
allowedTypes: {UniversalFileType.image},
|
||||
),
|
||||
builder: (context) =>
|
||||
CloudFilePicker(allowedTypes: {UniversalFileType.image}),
|
||||
).then((value) {
|
||||
if (value == null) return;
|
||||
image.value = value[0].id;
|
||||
@@ -412,8 +388,8 @@ class StickerForm extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'pack_detail.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(stickerPackContent)
|
||||
const stickerPackContentProvider = StickerPackContentFamily._();
|
||||
final stickerPackContentProvider = StickerPackContentFamily._();
|
||||
|
||||
final class StickerPackContentProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class StickerPackContentProvider
|
||||
FutureOr<List<SnSticker>>
|
||||
>
|
||||
with $FutureModifier<List<SnSticker>>, $FutureProvider<List<SnSticker>> {
|
||||
const StickerPackContentProvider._({
|
||||
StickerPackContentProvider._({
|
||||
required StickerPackContentFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -69,7 +69,7 @@ String _$stickerPackContentHash() =>
|
||||
|
||||
final class StickerPackContentFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<SnSticker>>, String> {
|
||||
const StickerPackContentFamily._()
|
||||
StickerPackContentFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'stickerPackContentProvider',
|
||||
@@ -86,7 +86,7 @@ final class StickerPackContentFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(stickerPackSticker)
|
||||
const stickerPackStickerProvider = StickerPackStickerFamily._();
|
||||
final stickerPackStickerProvider = StickerPackStickerFamily._();
|
||||
|
||||
final class StickerPackStickerProvider
|
||||
extends
|
||||
@@ -96,7 +96,7 @@ final class StickerPackStickerProvider
|
||||
FutureOr<SnSticker?>
|
||||
>
|
||||
with $FutureModifier<SnSticker?>, $FutureProvider<SnSticker?> {
|
||||
const StickerPackStickerProvider._({
|
||||
StickerPackStickerProvider._({
|
||||
required StickerPackStickerFamily super.from,
|
||||
required StickerWithPackQuery? super.argument,
|
||||
}) : super(
|
||||
@@ -145,7 +145,7 @@ String _$stickerPackStickerHash() =>
|
||||
final class StickerPackStickerFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<FutureOr<SnSticker?>, StickerWithPackQuery?> {
|
||||
const StickerPackStickerFamily._()
|
||||
StickerPackStickerFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'stickerPackStickerProvider',
|
||||
|
||||
@@ -140,7 +140,7 @@ final stickerPacksProvider = AsyncNotifierProvider.family.autoDispose(
|
||||
StickerPacksNotifier.new,
|
||||
);
|
||||
|
||||
class StickerPacksNotifier extends AsyncNotifier<List<SnStickerPack>>
|
||||
class StickerPacksNotifier extends AsyncNotifier<PaginationState<SnStickerPack>>
|
||||
with AsyncPaginationController<SnStickerPack> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'stickers.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(stickerPack)
|
||||
const stickerPackProvider = StickerPackFamily._();
|
||||
final stickerPackProvider = StickerPackFamily._();
|
||||
|
||||
final class StickerPackProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class StickerPackProvider
|
||||
FutureOr<SnStickerPack?>
|
||||
>
|
||||
with $FutureModifier<SnStickerPack?>, $FutureProvider<SnStickerPack?> {
|
||||
const StickerPackProvider._({
|
||||
StickerPackProvider._({
|
||||
required StickerPackFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -68,7 +68,7 @@ String _$stickerPackHash() => r'71ef84471237c8191918095094bdfc87d3920e77';
|
||||
|
||||
final class StickerPackFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnStickerPack?>, String?> {
|
||||
const StickerPackFamily._()
|
||||
StickerPackFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'stickerPackProvider',
|
||||
|
||||
@@ -21,6 +21,7 @@ import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/notification_tile.dart';
|
||||
import 'package:island/widgets/post/post_featured.dart';
|
||||
import 'package:island/widgets/check_in.dart';
|
||||
import 'package:island/screens/auth/login_modal.dart';
|
||||
import 'package:island/models/activity.dart';
|
||||
import 'package:island/screens/notification.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
@@ -116,7 +117,11 @@ class DashboardGrid extends HookConsumerWidget {
|
||||
topRight: isWide ? 0 : 12,
|
||||
)
|
||||
.padding(horizontal: isWide ? 0 : 16),
|
||||
),
|
||||
)
|
||||
else
|
||||
Center(
|
||||
child: _UnauthorizedCard(isWide: isWide),
|
||||
).padding(horizontal: isWide ? 24 : 16),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -303,7 +308,9 @@ class ClockCard extends HookConsumerWidget {
|
||||
spacing: 5,
|
||||
children: [
|
||||
notableDay.when(
|
||||
data: (day) => _buildNotableDayText(context, day!),
|
||||
data: (day) => day == null
|
||||
? Text('unauthorized').tr()
|
||||
: _buildNotableDayText(context, day),
|
||||
error: (err, _) =>
|
||||
Text(err.toString()).fontSize(12),
|
||||
loading: () =>
|
||||
@@ -412,11 +419,11 @@ class NotificationsCard extends HookConsumerWidget {
|
||||
loading: () => const SkeletonNotificationTile(),
|
||||
error: (error, stack) => Center(child: Text('Error: $error')),
|
||||
data: (notificationList) {
|
||||
if (notificationList.isEmpty) {
|
||||
if (notificationList.items.isEmpty) {
|
||||
return Center(child: Text('noNotificationsYet').tr());
|
||||
}
|
||||
// Get the most recent notification (first in the list)
|
||||
final recentNotification = notificationList.first;
|
||||
final recentNotification = notificationList.items.first;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -555,3 +562,64 @@ class FortuneCard extends HookConsumerWidget {
|
||||
).height(48);
|
||||
}
|
||||
}
|
||||
|
||||
class _UnauthorizedCard extends HookConsumerWidget {
|
||||
final bool isWide;
|
||||
const _UnauthorizedCard({required this.isWide});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: isWide ? 48 : 32,
|
||||
vertical: 32,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Gap(16),
|
||||
Icon(
|
||||
Symbols.dashboard_rounded,
|
||||
size: 64,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fill: 1,
|
||||
),
|
||||
const Gap(16),
|
||||
Text(
|
||||
'Welcome to\nthe Solar Network',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'Login to access your personalized dashboard with friends, notifications, chats, and more!',
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Gap(12),
|
||||
FilledButton.icon(
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => const LoginModal(),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Symbols.login),
|
||||
label: Text('login').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ class _AppOverview extends StatelessWidget {
|
||||
left: 20,
|
||||
bottom: -32,
|
||||
child: ProfilePictureWidget(
|
||||
fileId: app.picture?.id,
|
||||
file: app.picture,
|
||||
radius: 40,
|
||||
fallbackIcon: Symbols.apps,
|
||||
),
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'app_secrets.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(customAppSecrets)
|
||||
const customAppSecretsProvider = CustomAppSecretsFamily._();
|
||||
final customAppSecretsProvider = CustomAppSecretsFamily._();
|
||||
|
||||
final class CustomAppSecretsProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class CustomAppSecretsProvider
|
||||
with
|
||||
$FutureModifier<List<CustomAppSecret>>,
|
||||
$FutureProvider<List<CustomAppSecret>> {
|
||||
const CustomAppSecretsProvider._({
|
||||
CustomAppSecretsProvider._({
|
||||
required CustomAppSecretsFamily super.from,
|
||||
required (String, String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -74,7 +74,7 @@ final class CustomAppSecretsFamily extends $Family
|
||||
FutureOr<List<CustomAppSecret>>,
|
||||
(String, String, String)
|
||||
> {
|
||||
const CustomAppSecretsFamily._()
|
||||
CustomAppSecretsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'customAppSecretsProvider',
|
||||
|
||||
@@ -153,7 +153,7 @@ class CustomAppsScreen extends HookConsumerWidget {
|
||||
ListTile(
|
||||
title: Text(app.name),
|
||||
leading: ProfilePictureWidget(
|
||||
fileId: app.picture?.id,
|
||||
file: app.picture,
|
||||
fallbackIcon: Symbols.apps,
|
||||
),
|
||||
subtitle: Text(
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'apps.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(customApp)
|
||||
const customAppProvider = CustomAppFamily._();
|
||||
final customAppProvider = CustomAppFamily._();
|
||||
|
||||
final class CustomAppProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class CustomAppProvider
|
||||
FutureOr<CustomApp>
|
||||
>
|
||||
with $FutureModifier<CustomApp>, $FutureProvider<CustomApp> {
|
||||
const CustomAppProvider._({
|
||||
CustomAppProvider._({
|
||||
required CustomAppFamily super.from,
|
||||
required (String, String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -71,7 +71,7 @@ final class CustomAppFamily extends $Family
|
||||
FutureOr<CustomApp>,
|
||||
(String, String, String)
|
||||
> {
|
||||
const CustomAppFamily._()
|
||||
CustomAppFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'customAppProvider',
|
||||
@@ -94,7 +94,7 @@ final class CustomAppFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(customApps)
|
||||
const customAppsProvider = CustomAppsFamily._();
|
||||
final customAppsProvider = CustomAppsFamily._();
|
||||
|
||||
final class CustomAppsProvider
|
||||
extends
|
||||
@@ -104,7 +104,7 @@ final class CustomAppsProvider
|
||||
FutureOr<List<CustomApp>>
|
||||
>
|
||||
with $FutureModifier<List<CustomApp>>, $FutureProvider<List<CustomApp>> {
|
||||
const CustomAppsProvider._({
|
||||
CustomAppsProvider._({
|
||||
required CustomAppsFamily super.from,
|
||||
required (String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -153,7 +153,7 @@ String _$customAppsHash() => r'450bedaf4220b8963cb44afeb14d4c0e80f01b11';
|
||||
final class CustomAppsFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<FutureOr<List<CustomApp>>, (String, String)> {
|
||||
const CustomAppsFamily._()
|
||||
CustomAppsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'customAppsProvider',
|
||||
|
||||
@@ -143,7 +143,7 @@ class _BotOverview extends StatelessWidget {
|
||||
left: 20,
|
||||
bottom: -32,
|
||||
child: ProfilePictureWidget(
|
||||
fileId: bot.account.profile.picture?.id,
|
||||
file: bot.account.profile.picture,
|
||||
radius: 40,
|
||||
fallbackIcon: Symbols.smart_toy,
|
||||
),
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'bot_keys.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(botKeys)
|
||||
const botKeysProvider = BotKeysFamily._();
|
||||
final botKeysProvider = BotKeysFamily._();
|
||||
|
||||
final class BotKeysProvider
|
||||
extends
|
||||
@@ -22,7 +22,7 @@ final class BotKeysProvider
|
||||
with
|
||||
$FutureModifier<List<SnAccountApiKey>>,
|
||||
$FutureProvider<List<SnAccountApiKey>> {
|
||||
const BotKeysProvider._({
|
||||
BotKeysProvider._({
|
||||
required BotKeysFamily super.from,
|
||||
required (String, String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -74,7 +74,7 @@ final class BotKeysFamily extends $Family
|
||||
FutureOr<List<SnAccountApiKey>>,
|
||||
(String, String, String)
|
||||
> {
|
||||
const BotKeysFamily._()
|
||||
BotKeysFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'botKeysProvider',
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'bots.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(bots)
|
||||
const botsProvider = BotsFamily._();
|
||||
final botsProvider = BotsFamily._();
|
||||
|
||||
final class BotsProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class BotsProvider
|
||||
FutureOr<List<Bot>>
|
||||
>
|
||||
with $FutureModifier<List<Bot>>, $FutureProvider<List<Bot>> {
|
||||
const BotsProvider._({
|
||||
BotsProvider._({
|
||||
required BotsFamily super.from,
|
||||
required (String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -67,7 +67,7 @@ String _$botsHash() => r'15cefd5781350eb68208a342e85fcb0b9e0e3269';
|
||||
|
||||
final class BotsFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<Bot>>, (String, String)> {
|
||||
const BotsFamily._()
|
||||
BotsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'botsProvider',
|
||||
|
||||
@@ -51,10 +51,9 @@ class EditAppScreen extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isNew = id == null;
|
||||
final app =
|
||||
isNew
|
||||
? null
|
||||
: ref.watch(customAppProvider(publisherName, projectId, id!));
|
||||
final app = isNew
|
||||
? null
|
||||
: ref.watch(customAppProvider(publisherName, projectId, id!));
|
||||
|
||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||
|
||||
@@ -139,14 +138,10 @@ class EditAppScreen extends HookConsumerWidget {
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
final cloudFile =
|
||||
await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
).future;
|
||||
final cloudFile = await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(data: result, type: UniversalFileType.image),
|
||||
).future;
|
||||
if (cloudFile == null) {
|
||||
throw ArgumentError('Failed to upload the file...');
|
||||
}
|
||||
@@ -169,41 +164,40 @@ class EditAppScreen extends HookConsumerWidget {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder:
|
||||
(context) => SheetScaffold(
|
||||
titleText: 'addScope'.tr(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: scopeController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'scopeName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
builder: (context) => SheetScaffold(
|
||||
titleText: 'addScope'.tr(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: scopeController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'scopeName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () {
|
||||
if (scopeController.text.isNotEmpty) {
|
||||
allowedScopes.value = [
|
||||
...allowedScopes.value,
|
||||
scopeController.text,
|
||||
];
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Symbols.add),
|
||||
label: Text('add').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () {
|
||||
if (scopeController.text.isNotEmpty) {
|
||||
allowedScopes.value = [
|
||||
...allowedScopes.value,
|
||||
scopeController.text,
|
||||
];
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Symbols.add),
|
||||
label: Text('add').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -212,57 +206,56 @@ class EditAppScreen extends HookConsumerWidget {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder:
|
||||
(context) => SheetScaffold(
|
||||
titleText: 'addRedirectUri'.tr(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: uriController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'redirectUri'.tr(),
|
||||
hintText: 'https://example.com/auth/callback',
|
||||
helperText: 'redirectUriHint'.tr(),
|
||||
helperMaxLines: 3,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'uriRequired'.tr();
|
||||
}
|
||||
final uri = Uri.tryParse(value);
|
||||
if (uri == null || !uri.hasAbsolutePath) {
|
||||
return 'invalidUri'.tr();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
builder: (context) => SheetScaffold(
|
||||
titleText: 'addRedirectUri'.tr(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: uriController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'redirectUri'.tr(),
|
||||
hintText: 'https://example.com/auth/callback',
|
||||
helperText: 'redirectUriHint'.tr(),
|
||||
helperMaxLines: 3,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () {
|
||||
if (uriController.text.isNotEmpty) {
|
||||
redirectUris.value = [
|
||||
...redirectUris.value,
|
||||
uriController.text,
|
||||
];
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Symbols.add),
|
||||
label: Text('add').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'uriRequired'.tr();
|
||||
}
|
||||
final uri = Uri.tryParse(value);
|
||||
if (uri == null || !uri.hasAbsolutePath) {
|
||||
return 'invalidUri'.tr();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () {
|
||||
if (uriController.text.isNotEmpty) {
|
||||
redirectUris.value = [
|
||||
...redirectUris.value,
|
||||
uriController.text,
|
||||
];
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Symbols.add),
|
||||
label: Text('add').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -275,31 +268,28 @@ class EditAppScreen extends HookConsumerWidget {
|
||||
'picture_id': picture.value?.id,
|
||||
'background_id': background.value?.id,
|
||||
'links': {
|
||||
'home_page':
|
||||
homePageController.text.isNotEmpty
|
||||
? homePageController.text
|
||||
: null,
|
||||
'privacy_policy':
|
||||
privacyPolicyController.text.isNotEmpty
|
||||
? privacyPolicyController.text
|
||||
: null,
|
||||
'terms_of_service':
|
||||
termsController.text.isNotEmpty ? termsController.text : null,
|
||||
'home_page': homePageController.text.isNotEmpty
|
||||
? homePageController.text
|
||||
: null,
|
||||
'privacy_policy': privacyPolicyController.text.isNotEmpty
|
||||
? privacyPolicyController.text
|
||||
: null,
|
||||
'terms_of_service': termsController.text.isNotEmpty
|
||||
? termsController.text
|
||||
: null,
|
||||
},
|
||||
'oauth_config':
|
||||
oauthEnabled.value
|
||||
? {
|
||||
'redirect_uris': redirectUris.value,
|
||||
'post_logout_redirect_uris':
|
||||
postLogoutUris.value.isNotEmpty
|
||||
? postLogoutUris.value
|
||||
: null,
|
||||
'allowed_scopes': allowedScopes.value,
|
||||
'allowed_grant_types': allowedGrantTypes.value,
|
||||
'require_pkce': requirePkce.value,
|
||||
'allow_offline_access': allowOfflineAccess.value,
|
||||
}
|
||||
: null,
|
||||
'oauth_config': oauthEnabled.value
|
||||
? {
|
||||
'redirect_uris': redirectUris.value,
|
||||
'post_logout_redirect_uris': postLogoutUris.value.isNotEmpty
|
||||
? postLogoutUris.value
|
||||
: null,
|
||||
'allowed_scopes': allowedScopes.value,
|
||||
'allowed_grant_types': allowedGrantTypes.value,
|
||||
'require_pkce': requirePkce.value,
|
||||
'allow_offline_access': allowOfflineAccess.value,
|
||||
}
|
||||
: null,
|
||||
};
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
@@ -326,287 +316,269 @@ class EditAppScreen extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
final bodyContent =
|
||||
app == null && !isNew
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: app?.hasError == true && !isNew
|
||||
? ResponseErrorWidget(
|
||||
error: app!.error,
|
||||
onRetry:
|
||||
() => ref.invalidate(
|
||||
customAppProvider(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(),
|
||||
final bodyContent = app == null && !isNew
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: app?.hasError == true && !isNew
|
||||
? ResponseErrorWidget(
|
||||
error: app!.error,
|
||||
onRetry: () => ref.invalidate(
|
||||
customAppProvider(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(
|
||||
file: picture.value,
|
||||
radius: 40,
|
||||
fallbackIcon: Symbols.apps,
|
||||
),
|
||||
onTap: () {
|
||||
setPicture('background');
|
||||
setPicture('picture');
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
left: 20,
|
||||
bottom: -32,
|
||||
child: GestureDetector(
|
||||
child: ProfilePictureWidget(
|
||||
fileId: picture.value?.id,
|
||||
radius: 40,
|
||||
fallbackIcon: Symbols.apps,
|
||||
),
|
||||
onTap: () {
|
||||
setPicture('picture');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
).padding(bottom: 32),
|
||||
Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'name'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: slugController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'slug'.tr(),
|
||||
helperText: 'slugHint'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: descriptionController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'description'.tr(),
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
maxLines: 3,
|
||||
onTapOutside:
|
||||
(_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ExpansionPanelList(
|
||||
expansionCallback: (index, isExpanded) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
enableLinks.value = isExpanded;
|
||||
break;
|
||||
case 1:
|
||||
oauthEnabled.value = isExpanded;
|
||||
break;
|
||||
}
|
||||
},
|
||||
children: [
|
||||
ExpansionPanel(
|
||||
headerBuilder:
|
||||
(context, isExpanded) =>
|
||||
ListTile(title: Text('appLinks').tr()),
|
||||
body: Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: homePageController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'homePageUrl'.tr(),
|
||||
hintText: 'https://example.com',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
),
|
||||
TextFormField(
|
||||
controller: privacyPolicyController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'privacyPolicyUrl'.tr(),
|
||||
hintText: 'https://example.com/privacy',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
),
|
||||
TextFormField(
|
||||
controller: termsController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'termsOfServiceUrl'.tr(),
|
||||
hintText: 'https://example.com/terms',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 16, bottom: 24),
|
||||
isExpanded: enableLinks.value,
|
||||
),
|
||||
ExpansionPanel(
|
||||
headerBuilder:
|
||||
(context, isExpanded) =>
|
||||
ListTile(title: Text('oauthConfig').tr()),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('redirectUris'.tr()),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
...redirectUris.value.map(
|
||||
(uri) => ListTile(
|
||||
title: Text(uri),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Symbols.delete),
|
||||
onPressed: () {
|
||||
redirectUris.value =
|
||||
redirectUris.value
|
||||
.where((u) => u != uri)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (redirectUris.value.isNotEmpty)
|
||||
const Divider(height: 1),
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.add),
|
||||
title: Text('addRedirectUri'.tr()),
|
||||
onTap: showAddRedirectUriDialog,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
8,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text('allowedScopes'.tr()),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
...allowedScopes.value.map(
|
||||
(scope) => ListTile(
|
||||
title: Text(scope),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Symbols.delete),
|
||||
onPressed: () {
|
||||
allowedScopes.value =
|
||||
allowedScopes.value
|
||||
.where(
|
||||
(s) => s != scope,
|
||||
)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (allowedScopes.value.isNotEmpty)
|
||||
const Divider(height: 1),
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.add),
|
||||
title: Text('add').tr(),
|
||||
onTap: showAddScopeDialog,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SwitchListTile(
|
||||
title: Text('requirePkce'.tr()),
|
||||
value: requirePkce.value,
|
||||
onChanged:
|
||||
(value) => requirePkce.value = value,
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text('allowOfflineAccess'.tr()),
|
||||
value: allowOfflineAccess.value,
|
||||
onChanged:
|
||||
(value) =>
|
||||
allowOfflineAccess.value = value,
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 16, bottom: 24),
|
||||
isExpanded: oauthEnabled.value,
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
).padding(bottom: 32),
|
||||
Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'name'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: slugController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'slug'.tr(),
|
||||
helperText: 'slugHint'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: descriptionController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'description'.tr(),
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
maxLines: 3,
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ExpansionPanelList(
|
||||
expansionCallback: (index, isExpanded) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
enableLinks.value = isExpanded;
|
||||
break;
|
||||
case 1:
|
||||
oauthEnabled.value = isExpanded;
|
||||
break;
|
||||
}
|
||||
},
|
||||
children: [
|
||||
ExpansionPanel(
|
||||
headerBuilder: (context, isExpanded) =>
|
||||
ListTile(title: Text('appLinks').tr()),
|
||||
body: Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: homePageController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'homePageUrl'.tr(),
|
||||
hintText: 'https://example.com',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
),
|
||||
TextFormField(
|
||||
controller: privacyPolicyController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'privacyPolicyUrl'.tr(),
|
||||
hintText: 'https://example.com/privacy',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
),
|
||||
TextFormField(
|
||||
controller: termsController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'termsOfServiceUrl'.tr(),
|
||||
hintText: 'https://example.com/terms',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.url,
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 16, bottom: 24),
|
||||
isExpanded: enableLinks.value,
|
||||
),
|
||||
ExpansionPanel(
|
||||
headerBuilder: (context, isExpanded) =>
|
||||
ListTile(title: Text('oauthConfig').tr()),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('redirectUris'.tr()),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
...redirectUris.value.map(
|
||||
(uri) => ListTile(
|
||||
title: Text(uri),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Symbols.delete),
|
||||
onPressed: () {
|
||||
redirectUris.value = redirectUris
|
||||
.value
|
||||
.where((u) => u != uri)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (redirectUris.value.isNotEmpty)
|
||||
const Divider(height: 1),
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.add),
|
||||
title: Text('addRedirectUri'.tr()),
|
||||
onTap: showAddRedirectUriDialog,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
8,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text('allowedScopes'.tr()),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
...allowedScopes.value.map(
|
||||
(scope) => ListTile(
|
||||
title: Text(scope),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Symbols.delete),
|
||||
onPressed: () {
|
||||
allowedScopes.value =
|
||||
allowedScopes.value
|
||||
.where((s) => s != scope)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (allowedScopes.value.isNotEmpty)
|
||||
const Divider(height: 1),
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.add),
|
||||
title: Text('add').tr(),
|
||||
onTap: showAddScopeDialog,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SwitchListTile(
|
||||
title: Text('requirePkce'.tr()),
|
||||
value: requirePkce.value,
|
||||
onChanged: (value) =>
|
||||
requirePkce.value = value,
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text('allowOfflineAccess'.tr()),
|
||||
value: allowOfflineAccess.value,
|
||||
onChanged: (value) =>
|
||||
allowOfflineAccess.value = value,
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 16, bottom: 24),
|
||||
isExpanded: oauthEnabled.value,
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (isModal) {
|
||||
return bodyContent;
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'edit_app.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(customApp)
|
||||
const customAppProvider = CustomAppFamily._();
|
||||
final customAppProvider = CustomAppFamily._();
|
||||
|
||||
final class CustomAppProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class CustomAppProvider
|
||||
FutureOr<CustomApp?>
|
||||
>
|
||||
with $FutureModifier<CustomApp?>, $FutureProvider<CustomApp?> {
|
||||
const CustomAppProvider._({
|
||||
CustomAppProvider._({
|
||||
required CustomAppFamily super.from,
|
||||
required (String, String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -71,7 +71,7 @@ final class CustomAppFamily extends $Family
|
||||
FutureOr<CustomApp?>,
|
||||
(String, String, String)
|
||||
> {
|
||||
const CustomAppFamily._()
|
||||
CustomAppFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'customAppProvider',
|
||||
|
||||
@@ -50,8 +50,9 @@ class EditBotScreen extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isNew = id == null;
|
||||
final botData =
|
||||
isNew ? null : ref.watch(botProvider(publisherName, projectId, id!));
|
||||
final botData = isNew
|
||||
? null
|
||||
: ref.watch(botProvider(publisherName, projectId, id!));
|
||||
|
||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||
final submitting = useState(false);
|
||||
@@ -125,14 +126,10 @@ class EditBotScreen extends HookConsumerWidget {
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
final cloudFile =
|
||||
await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
).future;
|
||||
final cloudFile = await FileUploader.createCloudFile(
|
||||
ref: ref,
|
||||
fileData: UniversalFile(data: result, type: UniversalFileType.image),
|
||||
).future;
|
||||
if (cloudFile == null) {
|
||||
throw ArgumentError('Failed to upload the file...');
|
||||
}
|
||||
@@ -193,284 +190,267 @@ class EditBotScreen extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
final bodyContent =
|
||||
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(),
|
||||
final bodyContent = 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(
|
||||
file: picture.value,
|
||||
radius: 40,
|
||||
fallbackIcon: Symbols.smart_toy,
|
||||
),
|
||||
onTap: () {
|
||||
setPicture('background');
|
||||
setPicture('picture');
|
||||
},
|
||||
),
|
||||
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(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: nickController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'nickname'.tr(),
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: slugController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'slug'.tr(),
|
||||
helperText: 'slugHint'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: bioController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'bio'.tr(),
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
maxLines: 3,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: firstNameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'firstName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: middleNameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'middleName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: lastNameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'lastName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: genderController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'gender'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: pronounsController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'pronouns'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: locationController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'location'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: timeZoneController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'timeZone'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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.all(16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1,
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
).padding(bottom: 32),
|
||||
Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: nameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'name'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: nickController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'nickname'.tr(),
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: slugController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'slug'.tr(),
|
||||
helperText: 'slugHint'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: bioController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'bio'.tr(),
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
maxLines: 3,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: firstNameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'firstName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: middleNameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'middleName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: lastNameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'lastName'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: genderController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'gender'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: pronounsController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'pronouns'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: locationController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'location'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: timeZoneController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'timeZone'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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.all(16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (isModal) {
|
||||
return bodyContent;
|
||||
|
||||
@@ -10,12 +10,12 @@ part of 'edit_bot.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(bot)
|
||||
const botProvider = BotFamily._();
|
||||
final botProvider = BotFamily._();
|
||||
|
||||
final class BotProvider
|
||||
extends $FunctionalProvider<AsyncValue<Bot?>, Bot?, FutureOr<Bot?>>
|
||||
with $FutureModifier<Bot?>, $FutureProvider<Bot?> {
|
||||
const BotProvider._({
|
||||
BotProvider._({
|
||||
required BotFamily super.from,
|
||||
required (String, String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -62,7 +62,7 @@ String _$botHash() => r'7bec47bb2a4061a5babc6d6d19c3d4c320c91188';
|
||||
|
||||
final class BotFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<Bot?>, (String, String, String)> {
|
||||
const BotFamily._()
|
||||
BotFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'botProvider',
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'edit_project.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(devProject)
|
||||
const devProjectProvider = DevProjectFamily._();
|
||||
final devProjectProvider = DevProjectFamily._();
|
||||
|
||||
final class DevProjectProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class DevProjectProvider
|
||||
FutureOr<DevProject?>
|
||||
>
|
||||
with $FutureModifier<DevProject?>, $FutureProvider<DevProject?> {
|
||||
const DevProjectProvider._({
|
||||
DevProjectProvider._({
|
||||
required DevProjectFamily super.from,
|
||||
required (String, String) super.argument,
|
||||
}) : super(
|
||||
@@ -68,7 +68,7 @@ String _$devProjectHash() => r'd92be3f5cdc510c2a377615ed5c70622a6842bf2';
|
||||
|
||||
final class DevProjectFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<DevProject?>, (String, String)> {
|
||||
const DevProjectFamily._()
|
||||
DevProjectFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'devProjectProvider',
|
||||
|
||||
@@ -329,7 +329,7 @@ class DeveloperSelector extends HookConsumerWidget {
|
||||
minTileHeight: 48,
|
||||
leading: ProfilePictureWidget(
|
||||
radius: 16,
|
||||
fileId: item.publisher?.picture?.id,
|
||||
file: item.publisher?.picture,
|
||||
),
|
||||
title: Text(item.publisher!.nick),
|
||||
subtitle: Text('@${item.publisher!.name}'),
|
||||
@@ -348,7 +348,7 @@ class DeveloperSelector extends HookConsumerWidget {
|
||||
if (isReadOnly || currentDeveloper == null) {
|
||||
return ProfilePictureWidget(
|
||||
radius: 16,
|
||||
fileId: currentDeveloper?.publisher?.picture?.id,
|
||||
file: currentDeveloper?.publisher?.picture,
|
||||
).center().padding(right: 8);
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ class DeveloperSelector extends HookConsumerWidget {
|
||||
...developersMenu.map(
|
||||
(e) => ProfilePictureWidget(
|
||||
radius: 16,
|
||||
fileId: e.value?.publisher?.picture?.id,
|
||||
file: e.value?.publisher?.picture,
|
||||
).center().padding(right: 8),
|
||||
),
|
||||
];
|
||||
@@ -928,7 +928,7 @@ class _DeveloperEnrollmentSheet extends HookConsumerWidget {
|
||||
final publisher = items[index];
|
||||
return ListTile(
|
||||
leading: ProfilePictureWidget(
|
||||
fileId: publisher.picture?.id,
|
||||
file: publisher.picture,
|
||||
fallbackIcon: Symbols.group,
|
||||
),
|
||||
title: Text(publisher.nick),
|
||||
|
||||
@@ -10,7 +10,7 @@ part of 'hub.dart';
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(developerStats)
|
||||
const developerStatsProvider = DeveloperStatsFamily._();
|
||||
final developerStatsProvider = DeveloperStatsFamily._();
|
||||
|
||||
final class DeveloperStatsProvider
|
||||
extends
|
||||
@@ -20,7 +20,7 @@ final class DeveloperStatsProvider
|
||||
FutureOr<DeveloperStats?>
|
||||
>
|
||||
with $FutureModifier<DeveloperStats?>, $FutureProvider<DeveloperStats?> {
|
||||
const DeveloperStatsProvider._({
|
||||
DeveloperStatsProvider._({
|
||||
required DeveloperStatsFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
@@ -68,7 +68,7 @@ String _$developerStatsHash() => r'45546f29ec7cd1a9c3a4e0f4e39275e78bf34755';
|
||||
|
||||
final class DeveloperStatsFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<DeveloperStats?>, String?> {
|
||||
const DeveloperStatsFamily._()
|
||||
DeveloperStatsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'developerStatsProvider',
|
||||
@@ -85,7 +85,7 @@ final class DeveloperStatsFamily extends $Family
|
||||
}
|
||||
|
||||
@ProviderFor(developers)
|
||||
const developersProvider = DevelopersProvider._();
|
||||
final developersProvider = DevelopersProvider._();
|
||||
|
||||
final class DevelopersProvider
|
||||
extends
|
||||
@@ -97,7 +97,7 @@ final class DevelopersProvider
|
||||
with
|
||||
$FutureModifier<List<SnDeveloper>>,
|
||||
$FutureProvider<List<SnDeveloper>> {
|
||||
const DevelopersProvider._()
|
||||
DevelopersProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
@@ -126,7 +126,7 @@ final class DevelopersProvider
|
||||
String _$developersHash() => r'252341098617ac398ce133994453f318dd3edbd2';
|
||||
|
||||
@ProviderFor(devProjects)
|
||||
const devProjectsProvider = DevProjectsFamily._();
|
||||
final devProjectsProvider = DevProjectsFamily._();
|
||||
|
||||
final class DevProjectsProvider
|
||||
extends
|
||||
@@ -136,7 +136,7 @@ final class DevProjectsProvider
|
||||
FutureOr<List<DevProject>>
|
||||
>
|
||||
with $FutureModifier<List<DevProject>>, $FutureProvider<List<DevProject>> {
|
||||
const DevProjectsProvider._({
|
||||
DevProjectsProvider._({
|
||||
required DevProjectsFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
@@ -184,7 +184,7 @@ String _$devProjectsHash() => r'715b395bebda785d38691ffee3b88e50b498c91a';
|
||||
|
||||
final class DevProjectsFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<List<DevProject>>, String> {
|
||||
const DevProjectsFamily._()
|
||||
DevProjectsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'devProjectsProvider',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user