Compare commits

..

60 Commits

Author SHA1 Message Date
926ae5402f 🐛 Fix bugs 2025-10-29 01:50:27 +08:00
1a37d384e6 ♻️ Refactor watchOS content view 2025-10-29 01:26:27 +08:00
d4cf598f69 Image rendering on watchOS 2025-10-29 00:47:23 +08:00
0106c08891 🐛 Fix API requesting on watchOS app 2025-10-28 23:20:52 +08:00
9697def808 Watch connectivity on iOS 2025-10-28 23:16:44 +08:00
6572875229 🎉 Created a watchOS app that compiles 2025-10-28 22:29:05 +08:00
66590b9079 🐛 Fix ios native code 2025-10-28 22:19:51 +08:00
08b9604b55 🚀 Launch 3.3.0+138 (SNAPSHOT) (HOTFIX) 2025-10-28 18:51:20 +08:00
0602bbd277 🐛 Fix AppBar in SafeArea in explore 2025-10-28 13:08:52 +08:00
76e7ba7898 🚀 Launch 3.3.0+137 (SNAPSHOT) 2025-10-28 01:27:21 +08:00
6e6616b236 🐛 Fix NSE failed compiling 2025-10-28 01:26:57 +08:00
071d51b25e 👔 Account verification no longer showing along the individual publisher 2025-10-28 01:19:57 +08:00
a958362461 💄 Remove the circular progress gap in check in widget 2025-10-28 01:18:26 +08:00
6749bb00fe 🐛 Fix padding inconsistent in explore screen 2025-10-28 01:17:54 +08:00
11fb20c673 💄 Put appbar back to explore 2025-10-28 01:17:18 +08:00
a7990f83db ♻️ Refactored the post compose sheet 2025-10-28 01:10:18 +08:00
5f4cdf7937 Customizable fab location 2025-10-28 00:50:37 +08:00
3330ca14dd 🐛 Trying to fix the NSE again... 2025-10-28 00:24:55 +08:00
1719b1c8fe 🐛 Bug fixes 2025-10-27 01:57:03 +08:00
3c2c51bfaf 🐛 Fix post item color inconsistent with other card when set opacity of the card bg 2025-10-27 01:49:16 +08:00
239d6750ff 🐛 Fix duplicate verification mark 2025-10-27 01:47:38 +08:00
8b0c91977a 🐛 Fix think sheet didn't provide context 2025-10-27 01:45:54 +08:00
f74cca8464 💄 Optimize UI and UX for thought 2025-10-27 01:40:35 +08:00
08091d51bf ♻️ Refactor thought widgets 2025-10-27 01:08:42 +08:00
481190811b 💄 Optimize thinking UI 2025-10-27 00:56:21 +08:00
4b32b65d1c Think with messages 2025-10-27 00:23:35 +08:00
50ac7109bb 💄 Optimize thinking 2025-10-26 23:16:05 +08:00
62da279c71 Think based the post 2025-10-26 22:23:17 +08:00
fde6dbf891 🐛 Fix some bugs 2025-10-26 22:08:11 +08:00
613bf4fb42 💄 Optimize UX in AI thought 2025-10-26 22:04:34 +08:00
00ae586016 💄 Optimize post suggestion 2025-10-26 21:04:15 +08:00
ea0d132dce AI proposal 2025-10-26 20:57:35 +08:00
aa2df1e847 🐛 Fixes and optimizations 2025-10-26 18:45:14 +08:00
50672795f3 💄 UX Optimizations 2025-10-26 03:35:24 +08:00
383de9568d ♻️ Fab menu overhaul 2025-10-26 03:31:46 +08:00
01fa228e45 ♻️ Refactor markdown sticker rendering 2025-10-26 03:04:02 +08:00
1e71ad33a6 💄 Optimize UX 2025-10-26 03:00:09 +08:00
92c0260ecd 👽 Remove outdated field in sticker 2025-10-26 03:00:01 +08:00
0a161ad255 🐛 Dozens of bug fixes 2025-10-26 02:49:23 +08:00
c003f27b9a ⬆️ Upgrade cocoapods 2025-10-26 02:28:46 +08:00
19db8309c4 🌐 Localize the new feature: thinking 2025-10-26 01:46:49 +08:00
aa72ce08e8 🐛 Fix think sticky issue 2025-10-26 00:24:03 +08:00
4639b00b86 🐛 Fix AI topic won't be set 2025-10-26 00:15:21 +08:00
cc5460ea55 🐛 Fix thought seq id didn't update 2025-10-25 23:40:54 +08:00
eafac811e6 💄 Optimize thought sequence list 2025-10-25 23:37:17 +08:00
e3be691596 💄 Optimize the AI thought 2025-10-25 23:20:10 +08:00
aa180a1358 Ai thought basis 2025-10-25 23:01:32 +08:00
c2707b8af1 ♻️ Re-designed bottom nav 2025-10-25 21:50:43 +08:00
62fd0500f3 💄 Fix card transparency 2025-10-25 01:09:34 +08:00
eeae865cc8 💄 Optimize lotteries 2025-10-25 00:29:36 +08:00
cdf1413fe0 Lotteries 2025-10-25 00:18:08 +08:00
327b4c04f1 Message detail (action sheet) shows full sent at date 2025-10-24 00:50:51 +08:00
bd903ce29c 💄 Change realm bottom nav icon 2025-10-24 00:46:30 +08:00
1b8ecb15ce Post featured history 2025-10-24 00:45:34 +08:00
d4e380a97a ♻️ Moved the pinned to the metadata 2025-10-23 01:32:38 +08:00
126048b4fa 💄 Optimize post metadata 2025-10-23 01:27:40 +08:00
8bec18813d 💄 Optimize publisher name display 2025-10-23 00:38:37 +08:00
1ae81794b1 💥 Updated API routes 2025-10-22 22:51:51 +08:00
2a7d12de48 🐛 Fix bugs 2025-10-20 23:48:24 +08:00
64c60ead48 ⬆️ Upgrade deps 2025-10-20 23:40:30 +08:00
143 changed files with 9200 additions and 1007 deletions

View File

@@ -871,6 +871,7 @@
"pollShortTextAnswerPreview": "Short text answer (preview)",
"award": "Award",
"awardPost": "Award Post",
"awardPoints": "Awarded {} points",
"awardMessage": "Message",
"awardMessageHint": "Enter your award message...",
"awardAttitude": "Attitude",
@@ -1252,5 +1253,54 @@
"availableWithYourPlan": "Available with your plan",
"upgradeRequired": "Upgrade required",
"settingsDisableAnimation": "Disable Animation",
"addTag": "Add Tag"
"addTag": "Add Tag",
"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": "Function Call",
"aiThought": "AI Thought",
"aiThoughtTitle": "Let sn-chan think",
"postReferenceUnavailable": "Referenced post is unavailable",
"fabLocation": "FAB Location"
}

View File

@@ -1081,5 +1081,14 @@
"postPublish": "发布帖子",
"restoreDraftTitle": "恢复草稿",
"restoreDraftMessage": "发现了一个草稿。你想要恢复它吗?",
"draft": "草稿"
"draft": "草稿",
"thoughtDefaultTopic": "寻思",
"thoughtAiName": "SN 酱",
"thoughtUserName": "您",
"thoughtStreamingHint": "SN 酱正在思考...",
"thoughtInputHint": "问 SN 酱任何问题...",
"thoughtNewConversation": "开始新对话",
"thoughtParseError": "解析 AI 响应失败",
"aiThought": "寻思",
"aiThoughtTitle": "让 SN 酱寻思寻思"
}

View File

@@ -1,6 +1,3 @@
# Uncomment this line to define a global platform for your project
platform :ios, '15.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@@ -28,6 +25,8 @@ require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelpe
flutter_ios_podfile_setup
target 'Runner' do
platform :ios, '15.0'
use_frameworks!
use_modular_headers!
@@ -50,6 +49,16 @@ target 'Runner' do
end
end
target 'WatchRunner Watch App' do
platform :watchos, '11.0'
use_frameworks!
use_modular_headers!
pod 'Kingfisher', '~> 8.0'
pod 'KingfisherWebP'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)

View File

@@ -219,7 +219,22 @@ PODS:
- irondash_engine_context (0.0.1):
- Flutter
- Kingfisher (8.6.0)
- livekit_client (2.5.0):
- KingfisherWebP (1.7.2):
- Kingfisher (~> 8.0)
- libwebp (>= 1.1.0)
- libwebp (1.5.0):
- libwebp/demux (= 1.5.0)
- libwebp/mux (= 1.5.0)
- libwebp/sharpyuv (= 1.5.0)
- libwebp/webp (= 1.5.0)
- libwebp/demux (1.5.0):
- libwebp/webp
- libwebp/mux (1.5.0):
- libwebp/demux
- libwebp/sharpyuv (1.5.0)
- libwebp/webp (1.5.0):
- libwebp/sharpyuv
- livekit_client (2.5.3):
- Flutter
- flutter_webrtc
- WebRTC-SDK (= 137.7151.04)
@@ -333,6 +348,7 @@ DEPENDENCIES:
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
- Kingfisher (~> 8.0)
- KingfisherWebP
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
@@ -375,6 +391,8 @@ SPEC REPOS:
- GoogleDataTransport
- GoogleUtilities
- Kingfisher
- KingfisherWebP
- libwebp
- nanopb
- OrderedSet
- PromisesObjC
@@ -517,10 +535,12 @@ SPEC CHECKSUMS:
GoogleAppMeasurement: 1e718274b7e015cefd846ac1fcf7820c70dc017d
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
Kingfisher: 64278f126a815d0e2d391cdf71311b85882c4de0
livekit_client: a6f5fa86ac28ccd7ded53626a5379961db311ab4
KingfisherWebP: 38b9721821947f547afb78f933f75f4f9e0ae402
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
livekit_client: 86c8af579274e4b7a215185a8080db2d4e176f40
local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
@@ -529,8 +549,8 @@ SPEC CHECKSUMS:
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
pointer_interceptor_ios: ec847ef8b0915778bed2b2cef636f4d177fa8eed
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
pointer_interceptor_ios: da06a662d5bfd329602b45b2ab41bc0fb5fdb0f0
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
@@ -538,7 +558,7 @@ SPEC CHECKSUMS:
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
@@ -546,11 +566,11 @@ SPEC CHECKSUMS:
super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
PODFILE CHECKSUM: c818292390b02fa379036ea099713a332bd7193f
PODFILE CHECKSUM: 3096dc559be56aca856e757e1dc65ca039801e2e
COCOAPODS: 1.16.2

View File

@@ -3,13 +3,14 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
7310A7DF2EB10963002C0FD3 /* WatchRunner Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
73ACDFAD2E3D0E6100B63535 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */; };
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
@@ -20,6 +21,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
A1D34487886D362AC8B99B2E /* Pods_WatchRunner_Watch_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 802C1CFCA7F1E069AAEFB454 /* Pods_WatchRunner_Watch_App.framework */; };
B87C0E607033790E71B54D73 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6D834CA86410B09796B312B /* Pods_Runner.framework */; };
D174D53FF3E8EA943491A5CC /* Pods_SolianShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */; };
D1772CE196985AE8E8C9F2E5 /* Pods_SolianNotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */; };
@@ -58,6 +60,17 @@
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
7310A7DE2EB10963002C0FD3 /* Embed Watch Content */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
dstSubfolderSpec = 16;
files = (
7310A7DF2EB10963002C0FD3 /* WatchRunner Watch App.app in Embed Watch Content */,
);
name = "Embed Watch Content";
runOnlyForDeploymentPostprocessing = 0;
};
73268D1D2DEAFD670076E970 /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -84,6 +97,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchRunner Watch App.profile.xcconfig"; path = "Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App.profile.xcconfig"; sourceTree = "<group>"; };
14118AC858B441AB16B7309E /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
@@ -100,6 +114,7 @@
39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3A1C47BD29CC6AC2587D4DBE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WatchRunner Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
737E920B2DB6A9FF00BE9CDB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
@@ -111,6 +126,8 @@
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
802C1CFCA7F1E069AAEFB454 /* Pods_WatchRunner_Watch_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WatchRunner_Watch_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchRunner Watch App.debug.xcconfig"; path = "Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App.debug.xcconfig"; sourceTree = "<group>"; };
8B40620B1EEBB09456406A3C /* Pods-SolianNotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianNotificationService.profile.xcconfig"; path = "Target Support Files/Pods-SolianNotificationService/Pods-SolianNotificationService.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
@@ -120,6 +137,7 @@
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9AE244813FCDFAA941430393 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
A2EB1DAFDE9B8E6D88BBF7A3 /* Pods-WatchRunner Watch App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchRunner Watch App.release.xcconfig"; path = "Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App.release.xcconfig"; sourceTree = "<group>"; };
A499FDB2082EB000933AA8C5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
A85FF612AE7623A9934E57CE /* Pods-SolianShareExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianShareExtension.profile.xcconfig"; path = "Target Support Files/Pods-SolianShareExtension/Pods-SolianShareExtension.profile.xcconfig"; sourceTree = "<group>"; };
AA0CA8A3E15DEE023BB27438 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -162,6 +180,11 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = "WatchRunner Watch App";
sourceTree = "<group>";
};
73268D272DEB012A0076E970 /* Services */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
@@ -205,6 +228,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
7310A7D12EB10962002C0FD3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1D34487886D362AC8B99B2E /* Pods_WatchRunner_Watch_App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
73ACDFA82E3D0E6100B63535 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -258,6 +289,7 @@
7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */,
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */,
73ACDFB82E3D0E6100B63535 /* UIKit.framework */,
802C1CFCA7F1E069AAEFB454 /* Pods_WatchRunner_Watch_App.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -280,6 +312,9 @@
17FAB080A9C53193ABD9C15B /* Pods-SolianShareExtension.debug.xcconfig */,
27C66EFB5A705F1A822C3EB0 /* Pods-SolianShareExtension.release.xcconfig */,
A85FF612AE7623A9934E57CE /* Pods-SolianShareExtension.profile.xcconfig */,
86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */,
A2EB1DAFDE9B8E6D88BBF7A3 /* Pods-WatchRunner Watch App.release.xcconfig */,
103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -303,6 +338,7 @@
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
91E124CE95BCB4DCD890160D /* Pods */,
@@ -319,6 +355,7 @@
73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */,
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */,
);
name = Products;
sourceTree = "<group>";
@@ -363,6 +400,28 @@
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
7310A7D32EB10962002C0FD3 /* WatchRunner Watch App */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */;
buildPhases = (
DDEDA1BA6278B94F0F7B9B61 /* [CP] Check Pods Manifest.lock */,
7310A7D02EB10962002C0FD3 /* Sources */,
7310A7D12EB10962002C0FD3 /* Frameworks */,
7310A7D22EB10962002C0FD3 /* Resources */,
C74B07D6587D29C67A198025 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */,
);
name = "WatchRunner Watch App";
productName = "WatchRunner Watch App";
productReference = 7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */;
productType = "com.apple.product-type.application";
};
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 73ACDFCB2E3D0E6100B63535 /* Build configuration list for PBXNativeTarget "SolianBroadcastExtension" */;
@@ -434,6 +493,7 @@
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
73268D1D2DEAFD670076E970 /* Embed Foundation Extensions */,
7310A7DE2EB10963002C0FD3 /* Embed Watch Content */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
@@ -463,7 +523,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1640;
LastSwiftUpdateCheck = 2600;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
@@ -471,6 +531,9 @@
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
7310A7D32EB10962002C0FD3 = {
CreatedOnToolsVersion = 26.0.1;
};
73ACDFAA2E3D0E6100B63535 = {
CreatedOnToolsVersion = 16.4;
};
@@ -504,6 +567,7 @@
73CDD6792DEC00480059D95D /* SolianNotificationService */,
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
7310A7D32EB10962002C0FD3 /* WatchRunner Watch App */,
);
};
/* End PBXProject section */
@@ -516,6 +580,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
7310A7D22EB10962002C0FD3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
73ACDFA92E3D0E6100B63535 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -598,10 +669,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
@@ -659,10 +734,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
@@ -683,6 +762,49 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
C74B07D6587D29C67A198025 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
DDEDA1BA6278B94F0F7B9B61 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-WatchRunner Watch App-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
E86CDE9D6464F4F52B910856 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -734,6 +856,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
7310A7D02EB10962002C0FD3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
73ACDFA72E3D0E6100B63535 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -943,6 +1072,144 @@
};
name = Profile;
};
7310A7E02EB10963002C0FD3 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = W7HPZ53V6B;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 26.0;
};
name = Debug;
};
7310A7E12EB10963002C0FD3 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A2EB1DAFDE9B8E6D88BBF7A3 /* Pods-WatchRunner Watch App.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = W7HPZ53V6B;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 26.0;
};
name = Release;
};
7310A7E22EB10963002C0FD3 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = W7HPZ53V6B;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 26.0;
};
name = Profile;
};
73ACDFC42E3D0E6100B63535 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -1487,6 +1754,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7310A7E02EB10963002C0FD3 /* Debug */,
7310A7E12EB10963002C0FD3 /* Release */,
7310A7E22EB10963002C0FD3 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
73ACDFCB2E3D0E6100B63535 /* Build configuration list for PBXNativeTarget "SolianBroadcastExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -1,9 +1,11 @@
import Flutter
import UIKit
import WatchConnectivity
@main
@objc class AppDelegate: FlutterAppDelegate {
let notifyDelegate = NotifyDelegate()
private var watchConnectivityService: WatchConnectivityService?
override func application(
_ application: UIApplication,
@@ -28,6 +30,55 @@ import UIKit
GeneratedPluginRegistrant.register(with: self)
if WCSession.isSupported() {
watchConnectivityService = WatchConnectivityService()
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
class WatchConnectivityService: NSObject, WCSessionDelegate {
private let session: WCSession
override init() {
self.session = .default
super.init()
print("[iOS] Activating WCSession")
self.session.delegate = self
self.session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
if let error = error {
print("[iOS] WCSession activation failed with error: \(error.localizedDescription)")
return
}
print("[iOS] WCSession activated with state: \(activationState.rawValue)")
}
func sessionDidBecomeInactive(_ session: WCSession) {}
func sessionDidDeactivate(_ session: WCSession) {
session.activate()
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
print("[iOS] Received message: \(message)")
if let request = message["request"] as? String, request == "data" {
let token = UserDefaults.standard.getFlutterToken()
let serverUrl = UserDefaults.standard.getServerUrl()
print("[iOS] Retrieved token: \(token ?? "nil")")
print("[iOS] Retrieved serverUrl: \(serverUrl)")
var data: [String: Any] = ["serverUrl": serverUrl]
if let token = token {
data["token"] = token
}
print("[iOS] Replying with data: \(data)")
replyHandler(data)
}
}
}

View File

@@ -8,7 +8,7 @@
import Foundation
func getAttachmentUrl(for identifier: String) -> String {
let serverBaseUrl = "https://api.solian.app"
let serverBaseUrl = UserDefaults.standard.getServerUrl()
return identifier.starts(with: "http") ? identifier : "\(serverBaseUrl)/drive/files/\(identifier)"
}

View File

@@ -26,6 +26,6 @@ extension UserDefaults {
}
func getServerUrl(forKey key: String = "app_server_url") -> String {
return self.getFlutterValue(forKey: key) ?? "https://nt.solian.app"
return self.getFlutterValue(forKey: key) ?? "https://api.solian.app"
}
}

View File

@@ -85,15 +85,8 @@ class NotificationService: UNNotificationServiceExtension {
customIdentifier: nil
)
let intent = self.createMessageIntent(with: sender, meta: metaCopy, body: content.body)
self.donateInteraction(for: intent)
let updatedContent = try? request.content.updating(from: intent)
content.categoryIdentifier = "CHAT_MESSAGE"
if let updatedContent = updatedContent {
self.contentHandler?(updatedContent)
} else {
self.contentHandler?(content)
}
self.contentHandler?(content)
})
}

View File

@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,14 @@
{
"images" : [
{
"filename" : "icon.png",
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,15 @@
//
// ContentView.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/28.
//
import SwiftUI
// The root view of the app.
struct ContentView: View {
var body: some View {
ExploreView()
}
}

View File

@@ -0,0 +1,88 @@
//
// FlowLayout.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
// MARK: - Custom Layouts
struct FlowLayout: Layout {
var alignment: HorizontalAlignment = .leading
var spacing: CGFloat = 10
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let containerWidth = proposal.width ?? 0
let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
var currentX: CGFloat = 0
var currentY: CGFloat = 0
var lineHeight: CGFloat = 0
var totalHeight: CGFloat = 0
for size in sizes {
if currentX + size.width > containerWidth {
// New line
currentX = 0
currentY += lineHeight + spacing
totalHeight = currentY + size.height
lineHeight = 0
}
currentX += size.width + spacing
lineHeight = max(lineHeight, size.height)
}
totalHeight = currentY + lineHeight
return CGSize(width: containerWidth, height: totalHeight)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let containerWidth = bounds.width
let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
var currentX: CGFloat = 0
var currentY: CGFloat = 0
var lineHeight: CGFloat = 0
var lineElements: [(offset: Int, size: CGSize)] = []
func placeLine() {
let lineWidth = lineElements.map { $0.size.width }.reduce(0, +) + CGFloat(lineElements.count - 1) * spacing
var startX: CGFloat = 0
switch alignment {
case .leading:
startX = bounds.minX
case .center:
startX = bounds.minX + (containerWidth - lineWidth) / 2
case .trailing:
startX = bounds.maxX - lineWidth
default:
startX = bounds.minX
}
var xOffset = startX
for (offset, size) in lineElements {
subviews[offset].place(at: CGPoint(x: xOffset, y: bounds.minY + currentY), proposal: ProposedViewSize(size)) // Use bounds.minY + currentY
xOffset += size.width + spacing
}
lineElements.removeAll() // Clear elements for the next line
}
for (offset, size) in sizes.enumerated() {
if currentX + size.width > containerWidth && !lineElements.isEmpty {
// New line
placeLine()
currentX = 0
currentY += lineHeight + spacing
lineHeight = 0
}
lineElements.append((offset, size))
currentX += size.width + spacing
lineHeight = max(lineHeight, size.height)
}
placeLine() // Place the last line
}
}

View File

@@ -0,0 +1,126 @@
//
// Models.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import Foundation
// MARK: - Models
struct AppToken: Codable {
let token: String
}
struct SnActivity: Codable, Identifiable {
let id: String
let type: String
let data: ActivityData?
let createdAt: Date
}
enum ActivityData: Codable {
case post(SnPost)
case discovery(DiscoveryData)
case unknown
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let post = try? container.decode(SnPost.self) {
self = .post(post)
return
}
if let discoveryData = try? container.decode(DiscoveryData.self) {
self = .discovery(discoveryData)
return
}
self = .unknown
}
func encode(to encoder: Encoder) throws {
// Not needed for decoding
}
}
struct SnPost: Codable, Identifiable {
let id: String
let title: String?
let content: String?
let publisher: SnPublisher
let attachments: [SnCloudFile]
let tags: [SnPostTag]
}
struct DiscoveryData: Codable {
let items: [DiscoveryItem]
}
struct DiscoveryItem: Codable, Identifiable {
var id = UUID()
let type: String
let data: DiscoveryItemData
enum CodingKeys: String, CodingKey {
case type, data
}
}
enum DiscoveryItemData: Codable {
case realm(SnRealm)
case publisher(SnPublisher)
case article(SnWebArticle)
case unknown
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let realm = try? container.decode(SnRealm.self) {
self = .realm(realm)
return
}
if let publisher = try? container.decode(SnPublisher.self) {
self = .publisher(publisher)
return
}
if let article = try? container.decode(SnWebArticle.self) {
self = .article(article)
return
}
self = .unknown
}
func encode(to encoder: Encoder) throws {
// Not needed for decoding
}
}
struct SnRealm: Codable, Identifiable {
let id: String
let name: String
let description: String?
}
struct SnPublisher: Codable, Identifiable {
let id: String
let name: String
let nick: String?
let description: String?
let picture: SnCloudFile?
}
struct SnCloudFile: Codable, Identifiable {
let id: String
let mimeType: String?
}
struct SnPostTag: Codable, Identifiable {
let id: String
let slug: String
let name: String?
}
struct SnWebArticle: Codable, Identifiable {
let id: String
let title: String
let url: String
}

View File

@@ -0,0 +1,15 @@
//
// CustomPreviews.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
#Preview {
NavigationStack {
ActivityListView(filter: "Preview", mockActivities: SnActivity.mock)
.environmentObject(AppState())
}
}

View File

@@ -0,0 +1,35 @@
//
// MockData.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import Foundation
#if DEBUG
extension SnActivity {
static var mock: [SnActivity] {
let mockPublisher = SnPublisher(id: "pub1", name: "Mock Publisher", nick: "mock_nick", description: "A publisher for testing", picture: SnCloudFile(id: "mock_avatar_id", mimeType: "image/png"))
let mockTag1 = SnPostTag(id: "tag1", slug: "swiftui", name: "SwiftUI")
let mockTag2 = SnPostTag(id: "tag2", slug: "watchos", name: "watchOS")
let mockAttachment1 = SnCloudFile(id: "mock_image_id_1", mimeType: "image/jpeg")
let mockAttachment2 = SnCloudFile(id: "mock_image_id_2", mimeType: "image/png")
let post1 = SnPost(id: "1", title: "Hello from a Mock Post!", content: "This is a mock post content. It can be a bit longer to see how it wraps.", publisher: mockPublisher, attachments: [mockAttachment1, mockAttachment2], tags: [mockTag1, mockTag2])
let activity1 = SnActivity(id: "1", type: "posts.new", data: .post(post1), createdAt: Date())
let realm1 = SnRealm(id: "r1", name: "SwiftUI Previews", description: "A place for designing in previews.")
let publisher1 = SnPublisher(id: "p1", name: "The Mock Times", nick: "mock_times", description: "All the news that's fit to mock.", picture: nil)
let article1 = SnWebArticle(id: "a1", title: "The Art of Mocking Data", url: "https://example.com")
let discoveryItem1 = DiscoveryItem(type: "realm", data: .realm(realm1))
let discoveryItem2 = DiscoveryItem(type: "publisher", data: .publisher(publisher1))
let discoveryItem3 = DiscoveryItem(type: "article", data: .article(article1))
let discoveryData = DiscoveryData(items: [discoveryItem1, discoveryItem2, discoveryItem3])
let activity2 = SnActivity(id: "2", type: "discovery", data: .discovery(discoveryData), createdAt: Date())
return [activity1, activity2]
}
}
#endif

View File

@@ -0,0 +1,103 @@
//
// ImageLoader.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
import Kingfisher
import KingfisherWebP
import Combine
// MARK: - Image Loader
@MainActor
class ImageLoader: ObservableObject {
@Published var image: Image?
@Published var errorMessage: String?
@Published var isLoading = false
private var dataTask: URLSessionDataTask?
private let session: URLSession
init(session: URLSession = .shared) {
self.session = session
}
deinit {
dataTask?.cancel()
}
func loadImage(from initialUrl: URL, token: String) async {
isLoading = true
errorMessage = nil
image = nil
do {
// First request with Authorization header
var request = URLRequest(url: initialUrl)
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
request.setValue("SolianWatch/1.0", forHTTPHeaderField: "User-Agent")
let (data, response) = try await session.data(for: request)
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 302, let redirectLocation = httpResponse.allHeaderFields["Location"] as? String, let redirectUrl = URL(string: redirectLocation) {
print("[watchOS] Redirecting to: \(redirectUrl)")
// Second request to the redirected URL (S3 signed URL) without Authorization header
let (redirectData, _) = try await session.data(from: redirectUrl)
if let uiImage = UIImage(data: redirectData) {
self.image = Image(uiImage: uiImage)
print("[watchOS] Image loaded successfully from redirect URL.")
} else {
// Try KingfisherWebP for WebP
let processor = WebPProcessor.default // Correct usage
if let kfImage = processor.process(item: .data(redirectData), options: KingfisherParsedOptionsInfo(
[
.processor(processor),
.loadDiskFileSynchronously,
.cacheOriginalImage
]
)) {
self.image = Image(uiImage: kfImage)
print("[watchOS] Image loaded successfully from redirect URL using KingfisherWebP.")
} else {
self.errorMessage = "Invalid image data from redirect (could not decode with KingfisherWebP)."
}
}
} else if httpResponse.statusCode == 200 {
if let uiImage = UIImage(data: data) {
self.image = Image(uiImage: uiImage)
print("[watchOS] Image loaded successfully from initial URL.")
} else {
// Try KingfisherWebP for WebP
let processor = WebPProcessor.default // Correct usage
if let kfImage = processor.process(item: .data(data), options: KingfisherParsedOptionsInfo(
[
.processor(processor),
.loadDiskFileSynchronously,
.cacheOriginalImage
]
)) {
self.image = Image(uiImage: kfImage)
print("[watchOS] Image loaded successfully from initial URL using KingfisherWebP.")
} else {
self.errorMessage = "Invalid image data (could not decode with KingfisherWebP)."
}
}
} else {
self.errorMessage = "HTTP Status Code: \(httpResponse.statusCode)"
}
}
} catch {
self.errorMessage = error.localizedDescription
print("[watchOS] Image loading failed: \(error.localizedDescription)")
}
isLoading = false
}
func cancel() {
dataTask?.cancel()
}
}

View File

@@ -0,0 +1,69 @@
//
// NetworkService.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import Foundation
// MARK: - Network Service
class NetworkService {
private let session = URLSession.shared
func fetchActivities(filter: String, cursor: String? = nil, token: String, serverUrl: String) async throws -> [SnActivity] {
guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL)
}
var components = URLComponents(url: baseURL.appendingPathComponent("/sphere/activities"), resolvingAgainstBaseURL: false)!
var queryItems = [URLQueryItem(name: "take", value: "20")]
if filter.lowercased() != "explore" {
queryItems.append(URLQueryItem(name: "filter", value: filter.lowercased()))
}
if let cursor = cursor {
queryItems.append(URLQueryItem(name: "cursor", value: cursor))
}
components.queryItems = queryItems
var request = URLRequest(url: components.url!)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
request.setValue("SolianWatch/1.0", forHTTPHeaderField: "User-Agent")
let (data, _) = try await session.data(for: request)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
decoder.keyDecodingStrategy = .convertFromSnakeCase
return try decoder.decode([SnActivity].self, from: data)
}
func createPost(title: String, content: String, token: String, serverUrl: String) async throws {
guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL)
}
let url = baseURL.appendingPathComponent("/sphere/posts")
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
request.setValue("SolianWatch/1.0", forHTTPHeaderField: "User-Agent")
let body: [String: Any] = ["title": title, "content": content]
request.httpBody = try JSONSerialization.data(withJSONObject: body)
let (data, response) = try await session.data(for: request)
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode != 201 {
let responseBody = String(data: data, encoding: .utf8) ?? ""
print("[watchOS] createPost failed with status code: \(httpResponse.statusCode), body: \(responseBody)")
throw URLError(URLError.Code(rawValue: httpResponse.statusCode))
}
}
}

View File

@@ -0,0 +1,38 @@
//
// AppState.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
import Combine
// MARK: - App State
@MainActor
class AppState: ObservableObject {
@Published var token: String? = nil
@Published var serverUrl: String? = nil
@Published var isReady = false
private var wcService = WatchConnectivityService()
private var cancellables = Set<AnyCancellable>()
init() {
wcService.$token.combineLatest(wcService.$serverUrl)
.receive(on: DispatchQueue.main)
.sink { [weak self] token, serverUrl in
self?.token = token
self?.serverUrl = serverUrl
if token != nil && serverUrl != nil {
self?.isReady = true
}
}
.store(in: &cancellables)
}
func requestData() {
wcService.requestDataFromPhone()
}
}

View File

@@ -0,0 +1,72 @@
//
// WatchConnectivityService.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import Foundation
import WatchConnectivity
import Combine
// MARK: - Watch Connectivity
class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
@Published var token: String?
@Published var serverUrl: String?
private let session: WCSession
override init() {
self.session = .default
super.init()
print("[watchOS] Activating WCSession")
self.session.delegate = self
self.session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
if let error = error {
print("[watchOS] WCSession activation failed with error: \(error.localizedDescription)")
return
}
print("[watchOS] WCSession activated with state: \(activationState.rawValue)")
if activationState == .activated {
requestDataFromPhone()
}
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
print("[watchOS] Received message: \(message)")
DispatchQueue.main.async {
if let token = message["token"] as? String {
self.token = token
}
if let serverUrl = message["serverUrl"] as? String {
self.serverUrl = serverUrl
}
}
}
func requestDataFromPhone() {
guard session.isReachable else {
print("[watchOS] Phone is not reachable")
return
}
print("[watchOS] Requesting data from phone")
session.sendMessage(["request": "data"]) { [weak self] response in
print("[watchOS] Received reply: \(response)")
DispatchQueue.main.async {
if let token = response["token"] as? String {
self?.token = token
}
if let serverUrl = response["serverUrl"] as? String {
self?.serverUrl = serverUrl
}
}
} errorHandler: { error in
print("[watchOS] sendMessage failed with error: \(error.localizedDescription)")
}
}
}

View File

@@ -0,0 +1,21 @@
//
// AttachmentUtils.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import Foundation
// MARK: - Helper Functions
func getAttachmentUrl(for fileId: String, serverUrl: String) -> URL? {
let urlString: String
if fileId.starts(with: "http") {
urlString = fileId
} else {
urlString = "\(serverUrl)/drive/files/\(fileId)"
}
print("[watchOS] Generated image URL: \(urlString)")
return URL(string: urlString)
}

View File

@@ -0,0 +1,50 @@
//
// ActivityViewModel.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import Foundation
import Combine
// MARK: - View Models
@MainActor
class ActivityViewModel: ObservableObject {
@Published var activities: [SnActivity] = []
@Published var isLoading = false
@Published var errorMessage: String?
private let networkService = NetworkService()
let filter: String
private var isMock = false
private var hasFetched = false // Add this
init(filter: String, mockActivities: [SnActivity]? = nil) {
self.filter = filter
if let mockActivities = mockActivities {
self.activities = mockActivities
self.isMock = true
}
}
func fetchActivities(token: String, serverUrl: String) async {
if isMock || hasFetched { return } // Check hasFetched
guard !isLoading else { return }
isLoading = true
errorMessage = nil
hasFetched = true // Set hasFetched
do {
let fetchedActivities = try await networkService.fetchActivities(filter: filter, token: token, serverUrl: serverUrl)
self.activities = fetchedActivities
} catch {
self.errorMessage = error.localizedDescription
print("[watchOS] fetchActivities failed with error: \(error)")
hasFetched = false // Reset on error
}
isLoading = false
}
}

View File

@@ -0,0 +1,35 @@
//
// ComposePostViewModel.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import Foundation
import Combine
@MainActor
class ComposePostViewModel: ObservableObject {
@Published var title = ""
@Published var content = ""
@Published var isPosting = false
@Published var errorMessage: String?
@Published var didPost = false
private let networkService = NetworkService()
func createPost(token: String, serverUrl: String) async {
guard !isPosting else { return }
isPosting = true
errorMessage = nil
do {
try await networkService.createPost(title: title, content: content, token: token, serverUrl: serverUrl)
didPost = true
} catch {
errorMessage = error.localizedDescription
}
isPosting = false
}
}

View File

@@ -0,0 +1,66 @@
//
// ActivityListView.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
// MARK: - Views
struct ActivityListView: View {
@StateObject private var viewModel: ActivityViewModel
@EnvironmentObject var appState: AppState
init(filter: String, mockActivities: [SnActivity]? = nil) {
_viewModel = StateObject(wrappedValue: ActivityViewModel(filter: filter, mockActivities: mockActivities))
}
var body: some View {
Group {
if viewModel.isLoading {
ProgressView()
} else if let errorMessage = viewModel.errorMessage {
VStack {
Text("Error fetching data")
.font(.headline)
Text(errorMessage)
.font(.caption)
.lineLimit(nil)
}
.padding()
} else if viewModel.activities.isEmpty {
Text("No activities found.")
} else {
List(viewModel.activities) { activity in
switch activity.type {
case "posts.new", "posts.new.replies":
if case .post(let post) = activity.data {
NavigationLink(
destination: PostDetailView(post: post).environmentObject(appState)
) {
PostRowView(post: post)
}
}
case "discovery":
if case .discovery(let discoveryData) = activity.data {
DiscoveryView(discoveryData: discoveryData)
}
default:
Text("Unknown activity type: \(activity.type)")
}
}
}
}
.onAppear {
if appState.isReady, let token = appState.token, let serverUrl = appState.serverUrl {
Task.detached {
await viewModel.fetchActivities(token: token, serverUrl: serverUrl)
}
}
}
.navigationTitle(viewModel.filter)
.navigationBarTitleDisplayMode(.inline)
}
}

View File

@@ -0,0 +1,38 @@
//
// AttachmentImageView.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
struct AttachmentImageView: View {
let attachment: SnCloudFile
@EnvironmentObject var appState: AppState
@StateObject private var imageLoader = ImageLoader()
var body: some View {
Group {
if imageLoader.isLoading {
ProgressView()
} else if let image = imageLoader.image {
image
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: .infinity)
} else if let errorMessage = imageLoader.errorMessage {
Text("Failed to load attachment: \(errorMessage)")
.font(.caption)
.foregroundColor(.red)
} else {
Text("File: \(attachment.id)")
}
}
.task(id: attachment.id) {
if let serverUrl = appState.serverUrl, let imageUrl = getAttachmentUrl(for: attachment.id, serverUrl: serverUrl), let token = appState.token, attachment.mimeType?.starts(with: "image") == true {
await imageLoader.loadImage(from: imageUrl, token: token)
}
}
}
}

View File

@@ -0,0 +1,52 @@
//
// ComposePostView.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
struct ComposePostView: View {
@StateObject private var viewModel = ComposePostViewModel()
@EnvironmentObject var appState: AppState
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationStack {
Form {
TextField("Title", text: $viewModel.title)
TextField("Content", text: $viewModel.content)
.frame(height: 100)
}
.navigationTitle("New Post")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
dismiss()
}
}
ToolbarItem(placement: .confirmationAction) {
Button("Post") {
Task {
if let token = appState.token, let serverUrl = appState.serverUrl {
await viewModel.createPost(token: token, serverUrl: serverUrl)
}
}
}
.disabled(viewModel.isPosting)
}
}
.onChange(of: viewModel.didPost) {
if viewModel.didPost {
dismiss()
}
}
.alert("Error", isPresented: .constant(viewModel.errorMessage != nil), actions: {
Button("OK") { viewModel.errorMessage = nil }
}, message: {
Text(viewModel.errorMessage ?? "")
})
}
}
}

View File

@@ -0,0 +1,110 @@
//
// DiscoveryViews.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
struct DiscoveryView: View {
let discoveryData: DiscoveryData
var body: some View {
NavigationLink(destination: DiscoveryDetailView(discoveryData: discoveryData)) {
VStack(alignment: .leading) {
Text("Discovery")
.font(.headline)
Text("\(discoveryData.items.count) new items to discover")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
}
struct DiscoveryDetailView: View {
let discoveryData: DiscoveryData
var body: some View {
List(discoveryData.items) { item in
NavigationLink(destination: destinationView(for: item)) {
itemView(for: item)
}
}
.navigationTitle("Discovery")
}
@ViewBuilder
private func itemView(for item: DiscoveryItem) -> some View {
VStack(alignment: .leading) {
switch item.data {
case .realm(let realm):
Text("Realm").font(.headline)
Text(realm.name).foregroundColor(.secondary)
case .publisher(let publisher):
Text("Publisher").font(.headline)
Text(publisher.name).foregroundColor(.secondary)
case .article(let article):
Text("Article").font(.headline)
Text(article.title).foregroundColor(.secondary)
case .unknown:
Text("Unknown item")
}
}
}
@ViewBuilder
private func destinationView(for item: DiscoveryItem) -> some View {
switch item.data {
case .realm(let realm):
RealmDetailView(realm: realm)
case .publisher(let publisher):
PublisherDetailView(publisher: publisher)
case .article(let article):
ArticleDetailView(article: article)
case .unknown:
Text("Detail view not available")
}
}
}
struct RealmDetailView: View {
let realm: SnRealm
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text(realm.name).font(.headline)
if let description = realm.description {
Text(description).font(.body)
}
}
.navigationTitle("Realm")
}
}
struct PublisherDetailView: View {
let publisher: SnPublisher
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text(publisher.name).font(.headline)
if let description = publisher.description {
Text(description).font(.body)
}
}
.navigationTitle("Publisher")
}
}
struct ArticleDetailView: View {
let article: SnWebArticle
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text(article.title).font(.headline)
Text(article.url).font(.caption).foregroundColor(.secondary)
}
.navigationTitle("Article")
}
}

View File

@@ -0,0 +1,59 @@
//
// ExploreView.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
// The main view with the TabView for filtering.
struct ExploreView: View {
@StateObject private var appState = AppState()
@State private var isComposing = false
@State private var selectedTab: String = "Explore"
var body: some View {
NavigationStack {
if appState.isReady {
TabView(selection: $selectedTab) {
ActivityListView(filter: "Explore")
.tag("Explore")
.tabItem {
Label("Explore", systemImage: "safari")
}
ActivityListView(filter: "Subscriptions")
.tag("Subscriptions")
.tabItem {
Label("Subscriptions", systemImage: "star")
}
ActivityListView(filter: "Friends")
.tag("Friends")
.tabItem {
Label("Friends", systemImage: "person.2")
}
}
.navigationTitle(selectedTab)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: { isComposing = true }) {
Label("Compose", systemImage: "plus")
}
}
}
.environmentObject(appState)
} else {
ProgressView { Text("Connecting to phone...") }
.onAppear {
appState.requestData()
}
}
}
.sheet(isPresented: $isComposing) {
ComposePostView()
.environmentObject(appState)
}
}
}

View File

@@ -0,0 +1,142 @@
//
// PostViews.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/29.
//
import SwiftUI
struct PostRowView: View {
let post: SnPost
@EnvironmentObject var appState: AppState
@StateObject private var imageLoader = ImageLoader() // Instantiate ImageLoader
var body: some View {
VStack(alignment: .leading, spacing: 4) {
HStack {
if let serverUrl = appState.serverUrl, let pictureId = post.publisher.picture?.id, let imageUrl = getAttachmentUrl(for: pictureId, serverUrl: serverUrl), let token = appState.token {
if imageLoader.isLoading {
ProgressView()
.frame(width: 24, height: 24)
} else if let image = imageLoader.image {
image
.resizable()
.frame(width: 24, height: 24)
.clipShape(Circle())
} else if let errorMessage = imageLoader.errorMessage {
Text("Failed: \(errorMessage)")
.font(.caption)
.foregroundColor(.red)
.frame(width: 24, height: 24)
} else {
// Placeholder if no image and not loading
Image(systemName: "person.circle.fill")
.resizable()
.frame(width: 24, height: 24)
.clipShape(Circle())
.foregroundColor(.gray)
}
}
Text(post.publisher.nick ?? post.publisher.name)
.font(.subheadline)
.bold()
}
.task(id: post.publisher.picture?.id) { // Use task(id:) to reload image when pictureId changes
if let serverUrl = appState.serverUrl, let pictureId = post.publisher.picture?.id, let imageUrl = getAttachmentUrl(for: pictureId, serverUrl: serverUrl), let token = appState.token {
await imageLoader.loadImage(from: imageUrl, token: token)
}
}
if let title = post.title, !title.isEmpty {
Text(title)
.font(.headline)
}
if let content = post.content, !content.isEmpty {
Text(content)
.font(.body)
}
}
}
}
struct PostDetailView: View {
let post: SnPost
@EnvironmentObject var appState: AppState
@StateObject private var publisherImageLoader = ImageLoader() // Instantiate ImageLoader for publisher avatar
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 8) {
HStack {
if let serverUrl = appState.serverUrl, let pictureId = post.publisher.picture?.id, let imageUrl = getAttachmentUrl(for: pictureId, serverUrl: serverUrl), let token = appState.token {
if publisherImageLoader.isLoading {
ProgressView()
.frame(width: 32, height: 32)
} else if let image = publisherImageLoader.image {
image
.resizable()
.frame(width: 32, height: 32)
.clipShape(Circle())
} else if let errorMessage = publisherImageLoader.errorMessage {
Text("Failed: \(errorMessage)")
.font(.caption)
.foregroundColor(.red)
.frame(width: 32, height: 32)
} else {
Image(systemName: "person.circle.fill")
.resizable()
.frame(width: 32, height: 32)
.clipShape(Circle())
.foregroundColor(.gray)
}
}
Text("@\(post.publisher.name)")
.font(.headline)
}
.task(id: post.publisher.picture?.id) { // Use task(id:) to reload image when pictureId changes
if let serverUrl = appState.serverUrl, let pictureId = post.publisher.picture?.id, let imageUrl = getAttachmentUrl(for: pictureId, serverUrl: serverUrl), let token = appState.token {
await publisherImageLoader.loadImage(from: imageUrl, token: token)
}
}
if let title = post.title, !title.isEmpty {
Text(title)
.font(.title2)
.bold()
}
if let content = post.content, !content.isEmpty {
Text(content)
.font(.body)
}
if !post.attachments.isEmpty {
Divider()
Text("Attachments").font(.headline)
ForEach(post.attachments) { attachment in
AttachmentImageView(attachment: attachment)
}
}
if !post.tags.isEmpty {
Divider()
Text("Tags").font(.headline)
FlowLayout(alignment: .leading, spacing: 4) {
ForEach(post.tags) { tag in
Text("#\(tag.name ?? tag.slug)")
.font(.caption)
.padding(.horizontal, 6)
.padding(.vertical, 3)
.background(Capsule().fill(Color.accentColor.opacity(0.2)))
.cornerRadius(5)
}
}
}
}
.padding()
}
.navigationTitle("Post")
}
}

View File

@@ -0,0 +1,17 @@
//
// WatchRunnerApp.swift
// WatchRunner Watch App
//
// Created by LittleSheep on 2025/10/28.
//
import SwiftUI
@main
struct WatchRunner_Watch_AppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

View File

@@ -47,9 +47,12 @@ sealed class SnPost with _$SnPost {
@Default([]) List<SnPostTag> tags,
@Default([]) List<SnPostCategory> categories,
@Default([]) List<dynamic> collections,
@Default([]) List<SnPostFeaturedRecord> featuredRecords,
@Default(null) DateTime? createdAt,
@Default(null) DateTime? updatedAt,
DateTime? deletedAt,
@Default(false) bool repliedGone,
@Default(false) bool forwardedGone,
@Default(false) bool isTruncated,
}) = _SnPost;
@@ -161,3 +164,19 @@ sealed class SnPostReaction with _$SnPostReaction {
factory SnPostReaction.fromJson(Map<String, dynamic> json) =>
_$SnPostReactionFromJson(json);
}
@freezed
sealed class SnPostFeaturedRecord with _$SnPostFeaturedRecord {
const factory SnPostFeaturedRecord({
required String id,
required String postId,
required DateTime? featuredAt,
required int socialCredits,
required DateTime createdAt,
required DateTime updatedAt,
required DateTime? deletedAt,
}) = _SnPostFeaturedRecord;
factory SnPostFeaturedRecord.fromJson(Map<String, dynamic> json) =>
_$SnPostFeaturedRecordFromJson(json);
}

View File

@@ -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; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated;
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; 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;
/// 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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.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));
}
@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),createdAt,updatedAt,deletedAt,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,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]);
@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, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, 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)';
}
@@ -48,7 +48,7 @@ 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, 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
});
@@ -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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? 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,}) {
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
@@ -102,10 +102,13 @@ as Map<String, bool>,reactions: null == reactions ? _self.reactions : reactions
as List<dynamic>,tags: null == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
as List<SnPostTag>,categories: null == categories ? _self.categories : categories // ignore: cast_nullable_to_non_nullable
as List<SnPostCategory>,collections: null == collections ? _self.collections : collections // ignore: cast_nullable_to_non_nullable
as List<dynamic>,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as List<dynamic>,featuredRecords: null == featuredRecords ? _self.featuredRecords : featuredRecords // ignore: cast_nullable_to_non_nullable
as List<SnPostFeaturedRecord>,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,isTruncated: null == isTruncated ? _self.isTruncated : isTruncated // ignore: cast_nullable_to_non_nullable
as DateTime?,repliedGone: null == repliedGone ? _self.repliedGone : repliedGone // ignore: cast_nullable_to_non_nullable
as bool,forwardedGone: null == forwardedGone ? _self.forwardedGone : forwardedGone // ignore: cast_nullable_to_non_nullable
as bool,isTruncated: null == isTruncated ? _self.isTruncated : isTruncated // ignore: cast_nullable_to_non_nullable
as bool,
));
}
@@ -257,10 +260,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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, 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;
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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.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 orElse();
}
@@ -278,10 +281,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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, 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;
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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);}
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.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);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -295,10 +298,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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, 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;
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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.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 null;
}
@@ -310,7 +313,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 [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections;
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.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;
factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
@override final String id;
@@ -398,9 +401,18 @@ class _SnPost implements SnPost {
return EqualUnmodifiableListView(_collections);
}
final List<SnPostFeaturedRecord> _featuredRecords;
@override@JsonKey() List<SnPostFeaturedRecord> get featuredRecords {
if (_featuredRecords is EqualUnmodifiableListView) return _featuredRecords;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_featuredRecords);
}
@override@JsonKey() final DateTime? createdAt;
@override@JsonKey() final DateTime? updatedAt;
@override final DateTime? deletedAt;
@override@JsonKey() final bool repliedGone;
@override@JsonKey() final bool forwardedGone;
@override@JsonKey() final bool isTruncated;
/// Create a copy of SnPost
@@ -416,16 +428,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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.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));
}
@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),createdAt,updatedAt,deletedAt,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,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]);
@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, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, 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)';
}
@@ -436,7 +448,7 @@ 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, 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
});
@@ -453,7 +465,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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? 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,}) {
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
@@ -490,10 +502,13 @@ as Map<String, bool>,reactions: null == reactions ? _self._reactions : reactions
as List<dynamic>,tags: null == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
as List<SnPostTag>,categories: null == categories ? _self._categories : categories // ignore: cast_nullable_to_non_nullable
as List<SnPostCategory>,collections: null == collections ? _self._collections : collections // ignore: cast_nullable_to_non_nullable
as List<dynamic>,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as List<dynamic>,featuredRecords: null == featuredRecords ? _self._featuredRecords : featuredRecords // ignore: cast_nullable_to_non_nullable
as List<SnPostFeaturedRecord>,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,isTruncated: null == isTruncated ? _self.isTruncated : isTruncated // ignore: cast_nullable_to_non_nullable
as DateTime?,repliedGone: null == repliedGone ? _self.repliedGone : repliedGone // ignore: cast_nullable_to_non_nullable
as bool,forwardedGone: null == forwardedGone ? _self.forwardedGone : forwardedGone // ignore: cast_nullable_to_non_nullable
as bool,isTruncated: null == isTruncated ? _self.isTruncated : isTruncated // ignore: cast_nullable_to_non_nullable
as bool,
));
}
@@ -2205,4 +2220,279 @@ $SnAccountCopyWith<$Res>? get account {
}
}
/// @nodoc
mixin _$SnPostFeaturedRecord {
String get id; String get postId; DateTime? get featuredAt; int get socialCredits; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
/// Create a copy of SnPostFeaturedRecord
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnPostFeaturedRecordCopyWith<SnPostFeaturedRecord> get copyWith => _$SnPostFeaturedRecordCopyWithImpl<SnPostFeaturedRecord>(this as SnPostFeaturedRecord, _$identity);
/// Serializes this SnPostFeaturedRecord to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostFeaturedRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.featuredAt, featuredAt) || other.featuredAt == featuredAt)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,postId,featuredAt,socialCredits,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnPostFeaturedRecord(id: $id, postId: $postId, featuredAt: $featuredAt, socialCredits: $socialCredits, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class $SnPostFeaturedRecordCopyWith<$Res> {
factory $SnPostFeaturedRecordCopyWith(SnPostFeaturedRecord value, $Res Function(SnPostFeaturedRecord) _then) = _$SnPostFeaturedRecordCopyWithImpl;
@useResult
$Res call({
String id, String postId, DateTime? featuredAt, int socialCredits, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
}
/// @nodoc
class _$SnPostFeaturedRecordCopyWithImpl<$Res>
implements $SnPostFeaturedRecordCopyWith<$Res> {
_$SnPostFeaturedRecordCopyWithImpl(this._self, this._then);
final SnPostFeaturedRecord _self;
final $Res Function(SnPostFeaturedRecord) _then;
/// Create a copy of SnPostFeaturedRecord
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? postId = null,Object? featuredAt = freezed,Object? socialCredits = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,featuredAt: freezed == featuredAt ? _self.featuredAt : featuredAt // ignore: cast_nullable_to_non_nullable
as DateTime?,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable
as int,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
}
/// Adds pattern-matching-related methods to [SnPostFeaturedRecord].
extension SnPostFeaturedRecordPatterns on SnPostFeaturedRecord {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnPostFeaturedRecord value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnPostFeaturedRecord() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnPostFeaturedRecord value) $default,){
final _that = this;
switch (_that) {
case _SnPostFeaturedRecord():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnPostFeaturedRecord value)? $default,){
final _that = this;
switch (_that) {
case _SnPostFeaturedRecord() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String postId, DateTime? featuredAt, int socialCredits, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnPostFeaturedRecord() when $default != null:
return $default(_that.id,_that.postId,_that.featuredAt,_that.socialCredits,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String postId, DateTime? featuredAt, int socialCredits, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
switch (_that) {
case _SnPostFeaturedRecord():
return $default(_that.id,_that.postId,_that.featuredAt,_that.socialCredits,_that.createdAt,_that.updatedAt,_that.deletedAt);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String postId, DateTime? featuredAt, int socialCredits, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
switch (_that) {
case _SnPostFeaturedRecord() when $default != null:
return $default(_that.id,_that.postId,_that.featuredAt,_that.socialCredits,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnPostFeaturedRecord implements SnPostFeaturedRecord {
const _SnPostFeaturedRecord({required this.id, required this.postId, required this.featuredAt, required this.socialCredits, required this.createdAt, required this.updatedAt, required this.deletedAt});
factory _SnPostFeaturedRecord.fromJson(Map<String, dynamic> json) => _$SnPostFeaturedRecordFromJson(json);
@override final String id;
@override final String postId;
@override final DateTime? featuredAt;
@override final int socialCredits;
@override final DateTime createdAt;
@override final DateTime updatedAt;
@override final DateTime? deletedAt;
/// Create a copy of SnPostFeaturedRecord
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnPostFeaturedRecordCopyWith<_SnPostFeaturedRecord> get copyWith => __$SnPostFeaturedRecordCopyWithImpl<_SnPostFeaturedRecord>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnPostFeaturedRecordToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostFeaturedRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.featuredAt, featuredAt) || other.featuredAt == featuredAt)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,postId,featuredAt,socialCredits,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnPostFeaturedRecord(id: $id, postId: $postId, featuredAt: $featuredAt, socialCredits: $socialCredits, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class _$SnPostFeaturedRecordCopyWith<$Res> implements $SnPostFeaturedRecordCopyWith<$Res> {
factory _$SnPostFeaturedRecordCopyWith(_SnPostFeaturedRecord value, $Res Function(_SnPostFeaturedRecord) _then) = __$SnPostFeaturedRecordCopyWithImpl;
@override @useResult
$Res call({
String id, String postId, DateTime? featuredAt, int socialCredits, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
}
/// @nodoc
class __$SnPostFeaturedRecordCopyWithImpl<$Res>
implements _$SnPostFeaturedRecordCopyWith<$Res> {
__$SnPostFeaturedRecordCopyWithImpl(this._self, this._then);
final _SnPostFeaturedRecord _self;
final $Res Function(_SnPostFeaturedRecord) _then;
/// Create a copy of SnPostFeaturedRecord
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? postId = null,Object? featuredAt = freezed,Object? socialCredits = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_SnPostFeaturedRecord(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,featuredAt: freezed == featuredAt ? _self.featuredAt : featuredAt // ignore: cast_nullable_to_non_nullable
as DateTime?,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable
as int,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
}
// dart format on

View File

@@ -85,6 +85,11 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
.toList() ??
const [],
collections: json['collections'] as List<dynamic>? ?? const [],
featuredRecords:
(json['featured_records'] as List<dynamic>?)
?.map((e) => SnPostFeaturedRecord.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
createdAt:
json['created_at'] == null
? null
@@ -97,6 +102,8 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
repliedGone: json['replied_gone'] as bool? ?? false,
forwardedGone: json['forwarded_gone'] as bool? ?? false,
isTruncated: json['is_truncated'] as bool? ?? false,
);
@@ -136,9 +143,12 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
'tags': instance.tags.map((e) => e.toJson()).toList(),
'categories': instance.categories.map((e) => e.toJson()).toList(),
'collections': instance.collections,
'featured_records': instance.featuredRecords.map((e) => e.toJson()).toList(),
'created_at': instance.createdAt?.toIso8601String(),
'updated_at': instance.updatedAt?.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
'replied_gone': instance.repliedGone,
'forwarded_gone': instance.forwardedGone,
'is_truncated': instance.isTruncated,
};
@@ -262,3 +272,33 @@ Map<String, dynamic> _$SnPostReactionToJson(_SnPostReaction instance) =>
'account': instance.account?.toJson(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};
_SnPostFeaturedRecord _$SnPostFeaturedRecordFromJson(
Map<String, dynamic> json,
) => _SnPostFeaturedRecord(
id: json['id'] as String,
postId: json['post_id'] as String,
featuredAt:
json['featured_at'] == null
? null
: DateTime.parse(json['featured_at'] as String),
socialCredits: (json['social_credits'] as num).toInt(),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$SnPostFeaturedRecordToJson(
_SnPostFeaturedRecord instance,
) => <String, dynamic>{
'id': instance.id,
'post_id': instance.postId,
'featured_at': instance.featuredAt?.toIso8601String(),
'social_credits': instance.socialCredits,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};

View File

@@ -10,7 +10,6 @@ sealed class SnSticker with _$SnSticker {
const factory SnSticker({
required String id,
required String slug,
required String imageId,
required SnCloudFile image,
required String packId,
required SnStickerPack? pack,

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$SnSticker {
String get id; String get slug; String get imageId; SnCloudFile get image; String get packId; SnStickerPack? get pack; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
String get id; String get slug; SnCloudFile get image; String get packId; SnStickerPack? get pack; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
/// Create a copy of SnSticker
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -28,16 +28,16 @@ $SnStickerCopyWith<SnSticker> get copyWith => _$SnStickerCopyWithImpl<SnSticker>
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnSticker&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.imageId, imageId) || other.imageId == imageId)&&(identical(other.image, image) || other.image == image)&&(identical(other.packId, packId) || other.packId == packId)&&(identical(other.pack, pack) || other.pack == pack)&&(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 SnSticker&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.image, image) || other.image == image)&&(identical(other.packId, packId) || other.packId == packId)&&(identical(other.pack, pack) || other.pack == pack)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,slug,imageId,image,packId,pack,createdAt,updatedAt,deletedAt);
int get hashCode => Object.hash(runtimeType,id,slug,image,packId,pack,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnSticker(id: $id, slug: $slug, imageId: $imageId, image: $image, packId: $packId, pack: $pack, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
return 'SnSticker(id: $id, slug: $slug, image: $image, packId: $packId, pack: $pack, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
@@ -48,7 +48,7 @@ abstract mixin class $SnStickerCopyWith<$Res> {
factory $SnStickerCopyWith(SnSticker value, $Res Function(SnSticker) _then) = _$SnStickerCopyWithImpl;
@useResult
$Res call({
String id, String slug, String imageId, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
String id, String slug, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
@@ -65,11 +65,10 @@ class _$SnStickerCopyWithImpl<$Res>
/// Create a copy of SnSticker
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? imageId = null,Object? image = null,Object? packId = null,Object? pack = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? image = null,Object? packId = null,Object? pack = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
as String,imageId: null == imageId ? _self.imageId : imageId // ignore: cast_nullable_to_non_nullable
as String,image: null == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
as SnCloudFile,packId: null == packId ? _self.packId : packId // ignore: cast_nullable_to_non_nullable
as String,pack: freezed == pack ? _self.pack : pack // ignore: cast_nullable_to_non_nullable
@@ -179,10 +178,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, String imageId, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String slug, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnSticker() when $default != null:
return $default(_that.id,_that.slug,_that.imageId,_that.image,_that.packId,_that.pack,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return $default(_that.id,_that.slug,_that.image,_that.packId,_that.pack,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return orElse();
}
@@ -200,10 +199,10 @@ return $default(_that.id,_that.slug,_that.imageId,_that.image,_that.packId,_that
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, String imageId, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String slug, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
switch (_that) {
case _SnSticker():
return $default(_that.id,_that.slug,_that.imageId,_that.image,_that.packId,_that.pack,_that.createdAt,_that.updatedAt,_that.deletedAt);}
return $default(_that.id,_that.slug,_that.image,_that.packId,_that.pack,_that.createdAt,_that.updatedAt,_that.deletedAt);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -217,10 +216,10 @@ return $default(_that.id,_that.slug,_that.imageId,_that.image,_that.packId,_that
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, String imageId, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String slug, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
switch (_that) {
case _SnSticker() when $default != null:
return $default(_that.id,_that.slug,_that.imageId,_that.image,_that.packId,_that.pack,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return $default(_that.id,_that.slug,_that.image,_that.packId,_that.pack,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return null;
}
@@ -232,12 +231,11 @@ return $default(_that.id,_that.slug,_that.imageId,_that.image,_that.packId,_that
@JsonSerializable()
class _SnSticker implements SnSticker {
const _SnSticker({required this.id, required this.slug, required this.imageId, required this.image, required this.packId, required this.pack, required this.createdAt, required this.updatedAt, required this.deletedAt});
const _SnSticker({required this.id, required this.slug, required this.image, required this.packId, required this.pack, required this.createdAt, required this.updatedAt, required this.deletedAt});
factory _SnSticker.fromJson(Map<String, dynamic> json) => _$SnStickerFromJson(json);
@override final String id;
@override final String slug;
@override final String imageId;
@override final SnCloudFile image;
@override final String packId;
@override final SnStickerPack? pack;
@@ -258,16 +256,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnSticker&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.imageId, imageId) || other.imageId == imageId)&&(identical(other.image, image) || other.image == image)&&(identical(other.packId, packId) || other.packId == packId)&&(identical(other.pack, pack) || other.pack == pack)&&(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 _SnSticker&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.image, image) || other.image == image)&&(identical(other.packId, packId) || other.packId == packId)&&(identical(other.pack, pack) || other.pack == pack)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,slug,imageId,image,packId,pack,createdAt,updatedAt,deletedAt);
int get hashCode => Object.hash(runtimeType,id,slug,image,packId,pack,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnSticker(id: $id, slug: $slug, imageId: $imageId, image: $image, packId: $packId, pack: $pack, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
return 'SnSticker(id: $id, slug: $slug, image: $image, packId: $packId, pack: $pack, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
@@ -278,7 +276,7 @@ abstract mixin class _$SnStickerCopyWith<$Res> implements $SnStickerCopyWith<$Re
factory _$SnStickerCopyWith(_SnSticker value, $Res Function(_SnSticker) _then) = __$SnStickerCopyWithImpl;
@override @useResult
$Res call({
String id, String slug, String imageId, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
String id, String slug, SnCloudFile image, String packId, SnStickerPack? pack, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
@@ -295,11 +293,10 @@ class __$SnStickerCopyWithImpl<$Res>
/// Create a copy of SnSticker
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? imageId = null,Object? image = null,Object? packId = null,Object? pack = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? image = null,Object? packId = null,Object? pack = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_SnSticker(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
as String,imageId: null == imageId ? _self.imageId : imageId // ignore: cast_nullable_to_non_nullable
as String,image: null == image ? _self.image : image // ignore: cast_nullable_to_non_nullable
as SnCloudFile,packId: null == packId ? _self.packId : packId // ignore: cast_nullable_to_non_nullable
as String,pack: freezed == pack ? _self.pack : pack // ignore: cast_nullable_to_non_nullable

View File

@@ -9,7 +9,6 @@ part of 'sticker.dart';
_SnSticker _$SnStickerFromJson(Map<String, dynamic> json) => _SnSticker(
id: json['id'] as String,
slug: json['slug'] as String,
imageId: json['image_id'] as String,
image: SnCloudFile.fromJson(json['image'] as Map<String, dynamic>),
packId: json['pack_id'] as String,
pack:
@@ -28,7 +27,6 @@ Map<String, dynamic> _$SnStickerToJson(_SnSticker instance) =>
<String, dynamic>{
'id': instance.id,
'slug': instance.slug,
'image_id': instance.imageId,
'image': instance.image.toJson(),
'pack_id': instance.packId,
'pack': instance.pack?.toJson(),

116
lib/models/thought.dart Normal file
View File

@@ -0,0 +1,116 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/file.dart';
part 'thought.freezed.dart';
part 'thought.g.dart';
enum ThinkingThoughtRole {
assistant(0),
user(1);
const ThinkingThoughtRole(this.value);
final int value;
static ThinkingThoughtRole fromValue(int value) {
return values.firstWhere((e) => e.value == value);
}
}
class ThinkingThoughtRoleConverter
implements JsonConverter<ThinkingThoughtRole, int> {
const ThinkingThoughtRoleConverter();
@override
ThinkingThoughtRole fromJson(int json) => ThinkingThoughtRole.fromValue(json);
@override
int toJson(ThinkingThoughtRole object) => object.value;
}
class ThinkingChunkTypeConverter
implements JsonConverter<ThinkingChunkType, int> {
const ThinkingChunkTypeConverter();
@override
ThinkingChunkType fromJson(int json) => ThinkingChunkType.fromValue(json);
@override
int toJson(ThinkingChunkType object) => object.value;
}
@freezed
sealed class StreamThinkingRequest with _$StreamThinkingRequest {
const factory StreamThinkingRequest({
required String userMessage,
String? sequenceId,
@Default([]) List<String> accpetProposals,
List<String>? attachedPosts,
List<Map<String, dynamic>>? attachedMessages,
}) = _StreamThinkingRequest;
factory StreamThinkingRequest.fromJson(Map<String, dynamic> json) =>
_$StreamThinkingRequestFromJson(json);
}
enum ThinkingChunkType {
text(0),
reasoning(1),
functionCall(2),
unknown(3);
const ThinkingChunkType(this.value);
final int value;
static ThinkingChunkType fromValue(int value) {
return values.firstWhere((e) => e.value == value);
}
}
@freezed
sealed class SnThinkingChunk with _$SnThinkingChunk {
const factory SnThinkingChunk({
@ThinkingChunkTypeConverter() required ThinkingChunkType type,
Map<String, dynamic>? data,
}) = _SnThinkingChunk;
factory SnThinkingChunk.fromJson(Map<String, dynamic> json) =>
_$SnThinkingChunkFromJson(json);
}
@freezed
sealed class SnThinkingSequence with _$SnThinkingSequence {
const factory SnThinkingSequence({
required String id,
String? topic,
@Default(0) int totalToken,
@Default(0) int paidToken,
required String accountId,
required DateTime createdAt,
required DateTime updatedAt,
DateTime? deletedAt,
}) = _SnThinkingSequence;
factory SnThinkingSequence.fromJson(Map<String, dynamic> json) =>
_$SnThinkingSequenceFromJson(json);
}
@freezed
sealed class SnThinkingThought with _$SnThinkingThought {
const factory SnThinkingThought({
required String id,
String? content,
@Default([]) List<SnCloudFile> files,
@Default([]) List<SnThinkingChunk> chunks,
@ThinkingThoughtRoleConverter() required ThinkingThoughtRole role,
int? tokenCount,
String? modelName,
required String sequenceId,
SnThinkingSequence? sequence,
required DateTime createdAt,
required DateTime updatedAt,
DateTime? deletedAt,
}) = _SnThinkingThought;
factory SnThinkingThought.fromJson(Map<String, dynamic> json) =>
_$SnThinkingThoughtFromJson(json);
}

File diff suppressed because it is too large Load Diff

128
lib/models/thought.g.dart Normal file
View File

@@ -0,0 +1,128 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'thought.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_StreamThinkingRequest _$StreamThinkingRequestFromJson(
Map<String, dynamic> json,
) => _StreamThinkingRequest(
userMessage: json['user_message'] as String,
sequenceId: json['sequence_id'] as String?,
accpetProposals:
(json['accpet_proposals'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const [],
attachedPosts:
(json['attached_posts'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
attachedMessages:
(json['attached_messages'] as List<dynamic>?)
?.map((e) => e as Map<String, dynamic>)
.toList(),
);
Map<String, dynamic> _$StreamThinkingRequestToJson(
_StreamThinkingRequest instance,
) => <String, dynamic>{
'user_message': instance.userMessage,
'sequence_id': instance.sequenceId,
'accpet_proposals': instance.accpetProposals,
'attached_posts': instance.attachedPosts,
'attached_messages': instance.attachedMessages,
};
_SnThinkingChunk _$SnThinkingChunkFromJson(Map<String, dynamic> json) =>
_SnThinkingChunk(
type: const ThinkingChunkTypeConverter().fromJson(
(json['type'] as num).toInt(),
),
data: json['data'] as Map<String, dynamic>?,
);
Map<String, dynamic> _$SnThinkingChunkToJson(_SnThinkingChunk instance) =>
<String, dynamic>{
'type': const ThinkingChunkTypeConverter().toJson(instance.type),
'data': instance.data,
};
_SnThinkingSequence _$SnThinkingSequenceFromJson(Map<String, dynamic> json) =>
_SnThinkingSequence(
id: json['id'] as String,
topic: json['topic'] as String?,
totalToken: (json['total_token'] as num?)?.toInt() ?? 0,
paidToken: (json['paid_token'] as num?)?.toInt() ?? 0,
accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$SnThinkingSequenceToJson(_SnThinkingSequence instance) =>
<String, dynamic>{
'id': instance.id,
'topic': instance.topic,
'total_token': instance.totalToken,
'paid_token': instance.paidToken,
'account_id': instance.accountId,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};
_SnThinkingThought _$SnThinkingThoughtFromJson(Map<String, dynamic> json) =>
_SnThinkingThought(
id: json['id'] as String,
content: json['content'] as String?,
files:
(json['files'] as List<dynamic>?)
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
chunks:
(json['chunks'] as List<dynamic>?)
?.map((e) => SnThinkingChunk.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
role: const ThinkingThoughtRoleConverter().fromJson(
(json['role'] as num).toInt(),
),
tokenCount: (json['token_count'] as num?)?.toInt(),
modelName: json['model_name'] as String?,
sequenceId: json['sequence_id'] as String,
sequence:
json['sequence'] == null
? null
: SnThinkingSequence.fromJson(
json['sequence'] as Map<String, dynamic>,
),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$SnThinkingThoughtToJson(_SnThinkingThought instance) =>
<String, dynamic>{
'id': instance.id,
'content': instance.content,
'files': instance.files.map((e) => e.toJson()).toList(),
'chunks': instance.chunks.map((e) => e.toJson()).toList(),
'role': const ThinkingThoughtRoleConverter().toJson(instance.role),
'token_count': instance.tokenCount,
'model_name': instance.modelName,
'sequence_id': instance.sequenceId,
'sequence': instance.sequence?.toJson(),
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};

View File

@@ -211,3 +211,44 @@ sealed class SnWalletFundRecipient with _$SnWalletFundRecipient {
factory SnWalletFundRecipient.fromJson(Map<String, dynamic> json) =>
_$SnWalletFundRecipientFromJson(json);
}
@freezed
sealed class SnLotteryTicket with _$SnLotteryTicket {
const factory SnLotteryTicket({
required String id,
required String accountId,
required SnAccount? account,
required List<int> regionOneNumbers,
required int regionTwoNumber,
required int multiplier,
required int drawStatus,
required DateTime? drawDate,
required List<int>? matchedRegionOneNumbers,
required int? matchedRegionTwoNumber,
required DateTime createdAt,
required DateTime updatedAt,
required DateTime? deletedAt,
}) = _SnLotteryTicket;
factory SnLotteryTicket.fromJson(Map<String, dynamic> json) =>
_$SnLotteryTicketFromJson(json);
}
@freezed
sealed class SnLotteryRecord with _$SnLotteryRecord {
const factory SnLotteryRecord({
required String id,
required DateTime drawDate,
required List<int> winningRegionOneNumbers,
required int winningRegionTwoNumber,
required int totalTickets,
required int totalPrizesAwarded,
required double totalPrizeAmount,
required DateTime createdAt,
required DateTime updatedAt,
required DateTime? deletedAt,
}) = _SnLotteryRecord;
factory SnLotteryRecord.fromJson(Map<String, dynamic> json) =>
_$SnLotteryRecordFromJson(json);
}

View File

@@ -3184,4 +3184,625 @@ $SnAccountCopyWith<$Res>? get recipientAccount {
}
}
/// @nodoc
mixin _$SnLotteryTicket {
String get id; String get accountId; SnAccount? get account; List<int> get regionOneNumbers; int get regionTwoNumber; int get multiplier; int get drawStatus; DateTime? get drawDate; List<int>? get matchedRegionOneNumbers; int? get matchedRegionTwoNumber; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
/// Create a copy of SnLotteryTicket
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnLotteryTicketCopyWith<SnLotteryTicket> get copyWith => _$SnLotteryTicketCopyWithImpl<SnLotteryTicket>(this as SnLotteryTicket, _$identity);
/// Serializes this SnLotteryTicket to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnLotteryTicket&&(identical(other.id, id) || other.id == id)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&const DeepCollectionEquality().equals(other.regionOneNumbers, regionOneNumbers)&&(identical(other.regionTwoNumber, regionTwoNumber) || other.regionTwoNumber == regionTwoNumber)&&(identical(other.multiplier, multiplier) || other.multiplier == multiplier)&&(identical(other.drawStatus, drawStatus) || other.drawStatus == drawStatus)&&(identical(other.drawDate, drawDate) || other.drawDate == drawDate)&&const DeepCollectionEquality().equals(other.matchedRegionOneNumbers, matchedRegionOneNumbers)&&(identical(other.matchedRegionTwoNumber, matchedRegionTwoNumber) || other.matchedRegionTwoNumber == matchedRegionTwoNumber)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,accountId,account,const DeepCollectionEquality().hash(regionOneNumbers),regionTwoNumber,multiplier,drawStatus,drawDate,const DeepCollectionEquality().hash(matchedRegionOneNumbers),matchedRegionTwoNumber,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnLotteryTicket(id: $id, accountId: $accountId, account: $account, regionOneNumbers: $regionOneNumbers, regionTwoNumber: $regionTwoNumber, multiplier: $multiplier, drawStatus: $drawStatus, drawDate: $drawDate, matchedRegionOneNumbers: $matchedRegionOneNumbers, matchedRegionTwoNumber: $matchedRegionTwoNumber, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class $SnLotteryTicketCopyWith<$Res> {
factory $SnLotteryTicketCopyWith(SnLotteryTicket value, $Res Function(SnLotteryTicket) _then) = _$SnLotteryTicketCopyWithImpl;
@useResult
$Res call({
String id, String accountId, SnAccount? account, List<int> regionOneNumbers, int regionTwoNumber, int multiplier, int drawStatus, DateTime? drawDate, List<int>? matchedRegionOneNumbers, int? matchedRegionTwoNumber, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
$SnAccountCopyWith<$Res>? get account;
}
/// @nodoc
class _$SnLotteryTicketCopyWithImpl<$Res>
implements $SnLotteryTicketCopyWith<$Res> {
_$SnLotteryTicketCopyWithImpl(this._self, this._then);
final SnLotteryTicket _self;
final $Res Function(SnLotteryTicket) _then;
/// Create a copy of SnLotteryTicket
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? accountId = null,Object? account = freezed,Object? regionOneNumbers = null,Object? regionTwoNumber = null,Object? multiplier = null,Object? drawStatus = null,Object? drawDate = freezed,Object? matchedRegionOneNumbers = freezed,Object? matchedRegionTwoNumber = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
as SnAccount?,regionOneNumbers: null == regionOneNumbers ? _self.regionOneNumbers : regionOneNumbers // ignore: cast_nullable_to_non_nullable
as List<int>,regionTwoNumber: null == regionTwoNumber ? _self.regionTwoNumber : regionTwoNumber // ignore: cast_nullable_to_non_nullable
as int,multiplier: null == multiplier ? _self.multiplier : multiplier // ignore: cast_nullable_to_non_nullable
as int,drawStatus: null == drawStatus ? _self.drawStatus : drawStatus // ignore: cast_nullable_to_non_nullable
as int,drawDate: freezed == drawDate ? _self.drawDate : drawDate // ignore: cast_nullable_to_non_nullable
as DateTime?,matchedRegionOneNumbers: freezed == matchedRegionOneNumbers ? _self.matchedRegionOneNumbers : matchedRegionOneNumbers // ignore: cast_nullable_to_non_nullable
as List<int>?,matchedRegionTwoNumber: freezed == matchedRegionTwoNumber ? _self.matchedRegionTwoNumber : matchedRegionTwoNumber // ignore: cast_nullable_to_non_nullable
as int?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
/// Create a copy of SnLotteryTicket
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountCopyWith<$Res>? get account {
if (_self.account == null) {
return null;
}
return $SnAccountCopyWith<$Res>(_self.account!, (value) {
return _then(_self.copyWith(account: value));
});
}
}
/// Adds pattern-matching-related methods to [SnLotteryTicket].
extension SnLotteryTicketPatterns on SnLotteryTicket {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnLotteryTicket value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnLotteryTicket() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnLotteryTicket value) $default,){
final _that = this;
switch (_that) {
case _SnLotteryTicket():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnLotteryTicket value)? $default,){
final _that = this;
switch (_that) {
case _SnLotteryTicket() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String accountId, SnAccount? account, List<int> regionOneNumbers, int regionTwoNumber, int multiplier, int drawStatus, DateTime? drawDate, List<int>? matchedRegionOneNumbers, int? matchedRegionTwoNumber, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnLotteryTicket() when $default != null:
return $default(_that.id,_that.accountId,_that.account,_that.regionOneNumbers,_that.regionTwoNumber,_that.multiplier,_that.drawStatus,_that.drawDate,_that.matchedRegionOneNumbers,_that.matchedRegionTwoNumber,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String accountId, SnAccount? account, List<int> regionOneNumbers, int regionTwoNumber, int multiplier, int drawStatus, DateTime? drawDate, List<int>? matchedRegionOneNumbers, int? matchedRegionTwoNumber, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
switch (_that) {
case _SnLotteryTicket():
return $default(_that.id,_that.accountId,_that.account,_that.regionOneNumbers,_that.regionTwoNumber,_that.multiplier,_that.drawStatus,_that.drawDate,_that.matchedRegionOneNumbers,_that.matchedRegionTwoNumber,_that.createdAt,_that.updatedAt,_that.deletedAt);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String accountId, SnAccount? account, List<int> regionOneNumbers, int regionTwoNumber, int multiplier, int drawStatus, DateTime? drawDate, List<int>? matchedRegionOneNumbers, int? matchedRegionTwoNumber, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
switch (_that) {
case _SnLotteryTicket() when $default != null:
return $default(_that.id,_that.accountId,_that.account,_that.regionOneNumbers,_that.regionTwoNumber,_that.multiplier,_that.drawStatus,_that.drawDate,_that.matchedRegionOneNumbers,_that.matchedRegionTwoNumber,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnLotteryTicket implements SnLotteryTicket {
const _SnLotteryTicket({required this.id, required this.accountId, required this.account, required final List<int> regionOneNumbers, required this.regionTwoNumber, required this.multiplier, required this.drawStatus, required this.drawDate, required final List<int>? matchedRegionOneNumbers, required this.matchedRegionTwoNumber, required this.createdAt, required this.updatedAt, required this.deletedAt}): _regionOneNumbers = regionOneNumbers,_matchedRegionOneNumbers = matchedRegionOneNumbers;
factory _SnLotteryTicket.fromJson(Map<String, dynamic> json) => _$SnLotteryTicketFromJson(json);
@override final String id;
@override final String accountId;
@override final SnAccount? account;
final List<int> _regionOneNumbers;
@override List<int> get regionOneNumbers {
if (_regionOneNumbers is EqualUnmodifiableListView) return _regionOneNumbers;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_regionOneNumbers);
}
@override final int regionTwoNumber;
@override final int multiplier;
@override final int drawStatus;
@override final DateTime? drawDate;
final List<int>? _matchedRegionOneNumbers;
@override List<int>? get matchedRegionOneNumbers {
final value = _matchedRegionOneNumbers;
if (value == null) return null;
if (_matchedRegionOneNumbers is EqualUnmodifiableListView) return _matchedRegionOneNumbers;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override final int? matchedRegionTwoNumber;
@override final DateTime createdAt;
@override final DateTime updatedAt;
@override final DateTime? deletedAt;
/// Create a copy of SnLotteryTicket
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnLotteryTicketCopyWith<_SnLotteryTicket> get copyWith => __$SnLotteryTicketCopyWithImpl<_SnLotteryTicket>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnLotteryTicketToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnLotteryTicket&&(identical(other.id, id) || other.id == id)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&const DeepCollectionEquality().equals(other._regionOneNumbers, _regionOneNumbers)&&(identical(other.regionTwoNumber, regionTwoNumber) || other.regionTwoNumber == regionTwoNumber)&&(identical(other.multiplier, multiplier) || other.multiplier == multiplier)&&(identical(other.drawStatus, drawStatus) || other.drawStatus == drawStatus)&&(identical(other.drawDate, drawDate) || other.drawDate == drawDate)&&const DeepCollectionEquality().equals(other._matchedRegionOneNumbers, _matchedRegionOneNumbers)&&(identical(other.matchedRegionTwoNumber, matchedRegionTwoNumber) || other.matchedRegionTwoNumber == matchedRegionTwoNumber)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,accountId,account,const DeepCollectionEquality().hash(_regionOneNumbers),regionTwoNumber,multiplier,drawStatus,drawDate,const DeepCollectionEquality().hash(_matchedRegionOneNumbers),matchedRegionTwoNumber,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnLotteryTicket(id: $id, accountId: $accountId, account: $account, regionOneNumbers: $regionOneNumbers, regionTwoNumber: $regionTwoNumber, multiplier: $multiplier, drawStatus: $drawStatus, drawDate: $drawDate, matchedRegionOneNumbers: $matchedRegionOneNumbers, matchedRegionTwoNumber: $matchedRegionTwoNumber, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class _$SnLotteryTicketCopyWith<$Res> implements $SnLotteryTicketCopyWith<$Res> {
factory _$SnLotteryTicketCopyWith(_SnLotteryTicket value, $Res Function(_SnLotteryTicket) _then) = __$SnLotteryTicketCopyWithImpl;
@override @useResult
$Res call({
String id, String accountId, SnAccount? account, List<int> regionOneNumbers, int regionTwoNumber, int multiplier, int drawStatus, DateTime? drawDate, List<int>? matchedRegionOneNumbers, int? matchedRegionTwoNumber, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
@override $SnAccountCopyWith<$Res>? get account;
}
/// @nodoc
class __$SnLotteryTicketCopyWithImpl<$Res>
implements _$SnLotteryTicketCopyWith<$Res> {
__$SnLotteryTicketCopyWithImpl(this._self, this._then);
final _SnLotteryTicket _self;
final $Res Function(_SnLotteryTicket) _then;
/// Create a copy of SnLotteryTicket
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? accountId = null,Object? account = freezed,Object? regionOneNumbers = null,Object? regionTwoNumber = null,Object? multiplier = null,Object? drawStatus = null,Object? drawDate = freezed,Object? matchedRegionOneNumbers = freezed,Object? matchedRegionTwoNumber = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_SnLotteryTicket(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
as SnAccount?,regionOneNumbers: null == regionOneNumbers ? _self._regionOneNumbers : regionOneNumbers // ignore: cast_nullable_to_non_nullable
as List<int>,regionTwoNumber: null == regionTwoNumber ? _self.regionTwoNumber : regionTwoNumber // ignore: cast_nullable_to_non_nullable
as int,multiplier: null == multiplier ? _self.multiplier : multiplier // ignore: cast_nullable_to_non_nullable
as int,drawStatus: null == drawStatus ? _self.drawStatus : drawStatus // ignore: cast_nullable_to_non_nullable
as int,drawDate: freezed == drawDate ? _self.drawDate : drawDate // ignore: cast_nullable_to_non_nullable
as DateTime?,matchedRegionOneNumbers: freezed == matchedRegionOneNumbers ? _self._matchedRegionOneNumbers : matchedRegionOneNumbers // ignore: cast_nullable_to_non_nullable
as List<int>?,matchedRegionTwoNumber: freezed == matchedRegionTwoNumber ? _self.matchedRegionTwoNumber : matchedRegionTwoNumber // ignore: cast_nullable_to_non_nullable
as int?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
/// Create a copy of SnLotteryTicket
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountCopyWith<$Res>? get account {
if (_self.account == null) {
return null;
}
return $SnAccountCopyWith<$Res>(_self.account!, (value) {
return _then(_self.copyWith(account: value));
});
}
}
/// @nodoc
mixin _$SnLotteryRecord {
String get id; DateTime get drawDate; List<int> get winningRegionOneNumbers; int get winningRegionTwoNumber; int get totalTickets; int get totalPrizesAwarded; double get totalPrizeAmount; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
/// Create a copy of SnLotteryRecord
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnLotteryRecordCopyWith<SnLotteryRecord> get copyWith => _$SnLotteryRecordCopyWithImpl<SnLotteryRecord>(this as SnLotteryRecord, _$identity);
/// Serializes this SnLotteryRecord to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnLotteryRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.drawDate, drawDate) || other.drawDate == drawDate)&&const DeepCollectionEquality().equals(other.winningRegionOneNumbers, winningRegionOneNumbers)&&(identical(other.winningRegionTwoNumber, winningRegionTwoNumber) || other.winningRegionTwoNumber == winningRegionTwoNumber)&&(identical(other.totalTickets, totalTickets) || other.totalTickets == totalTickets)&&(identical(other.totalPrizesAwarded, totalPrizesAwarded) || other.totalPrizesAwarded == totalPrizesAwarded)&&(identical(other.totalPrizeAmount, totalPrizeAmount) || other.totalPrizeAmount == totalPrizeAmount)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,drawDate,const DeepCollectionEquality().hash(winningRegionOneNumbers),winningRegionTwoNumber,totalTickets,totalPrizesAwarded,totalPrizeAmount,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnLotteryRecord(id: $id, drawDate: $drawDate, winningRegionOneNumbers: $winningRegionOneNumbers, winningRegionTwoNumber: $winningRegionTwoNumber, totalTickets: $totalTickets, totalPrizesAwarded: $totalPrizesAwarded, totalPrizeAmount: $totalPrizeAmount, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class $SnLotteryRecordCopyWith<$Res> {
factory $SnLotteryRecordCopyWith(SnLotteryRecord value, $Res Function(SnLotteryRecord) _then) = _$SnLotteryRecordCopyWithImpl;
@useResult
$Res call({
String id, DateTime drawDate, List<int> winningRegionOneNumbers, int winningRegionTwoNumber, int totalTickets, int totalPrizesAwarded, double totalPrizeAmount, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
}
/// @nodoc
class _$SnLotteryRecordCopyWithImpl<$Res>
implements $SnLotteryRecordCopyWith<$Res> {
_$SnLotteryRecordCopyWithImpl(this._self, this._then);
final SnLotteryRecord _self;
final $Res Function(SnLotteryRecord) _then;
/// Create a copy of SnLotteryRecord
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? drawDate = null,Object? winningRegionOneNumbers = null,Object? winningRegionTwoNumber = null,Object? totalTickets = null,Object? totalPrizesAwarded = null,Object? totalPrizeAmount = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,drawDate: null == drawDate ? _self.drawDate : drawDate // ignore: cast_nullable_to_non_nullable
as DateTime,winningRegionOneNumbers: null == winningRegionOneNumbers ? _self.winningRegionOneNumbers : winningRegionOneNumbers // ignore: cast_nullable_to_non_nullable
as List<int>,winningRegionTwoNumber: null == winningRegionTwoNumber ? _self.winningRegionTwoNumber : winningRegionTwoNumber // ignore: cast_nullable_to_non_nullable
as int,totalTickets: null == totalTickets ? _self.totalTickets : totalTickets // ignore: cast_nullable_to_non_nullable
as int,totalPrizesAwarded: null == totalPrizesAwarded ? _self.totalPrizesAwarded : totalPrizesAwarded // ignore: cast_nullable_to_non_nullable
as int,totalPrizeAmount: null == totalPrizeAmount ? _self.totalPrizeAmount : totalPrizeAmount // ignore: cast_nullable_to_non_nullable
as double,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
}
/// Adds pattern-matching-related methods to [SnLotteryRecord].
extension SnLotteryRecordPatterns on SnLotteryRecord {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnLotteryRecord value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnLotteryRecord() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnLotteryRecord value) $default,){
final _that = this;
switch (_that) {
case _SnLotteryRecord():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnLotteryRecord value)? $default,){
final _that = this;
switch (_that) {
case _SnLotteryRecord() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, DateTime drawDate, List<int> winningRegionOneNumbers, int winningRegionTwoNumber, int totalTickets, int totalPrizesAwarded, double totalPrizeAmount, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnLotteryRecord() when $default != null:
return $default(_that.id,_that.drawDate,_that.winningRegionOneNumbers,_that.winningRegionTwoNumber,_that.totalTickets,_that.totalPrizesAwarded,_that.totalPrizeAmount,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, DateTime drawDate, List<int> winningRegionOneNumbers, int winningRegionTwoNumber, int totalTickets, int totalPrizesAwarded, double totalPrizeAmount, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
switch (_that) {
case _SnLotteryRecord():
return $default(_that.id,_that.drawDate,_that.winningRegionOneNumbers,_that.winningRegionTwoNumber,_that.totalTickets,_that.totalPrizesAwarded,_that.totalPrizeAmount,_that.createdAt,_that.updatedAt,_that.deletedAt);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, DateTime drawDate, List<int> winningRegionOneNumbers, int winningRegionTwoNumber, int totalTickets, int totalPrizesAwarded, double totalPrizeAmount, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
switch (_that) {
case _SnLotteryRecord() when $default != null:
return $default(_that.id,_that.drawDate,_that.winningRegionOneNumbers,_that.winningRegionTwoNumber,_that.totalTickets,_that.totalPrizesAwarded,_that.totalPrizeAmount,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnLotteryRecord implements SnLotteryRecord {
const _SnLotteryRecord({required this.id, required this.drawDate, required final List<int> winningRegionOneNumbers, required this.winningRegionTwoNumber, required this.totalTickets, required this.totalPrizesAwarded, required this.totalPrizeAmount, required this.createdAt, required this.updatedAt, required this.deletedAt}): _winningRegionOneNumbers = winningRegionOneNumbers;
factory _SnLotteryRecord.fromJson(Map<String, dynamic> json) => _$SnLotteryRecordFromJson(json);
@override final String id;
@override final DateTime drawDate;
final List<int> _winningRegionOneNumbers;
@override List<int> get winningRegionOneNumbers {
if (_winningRegionOneNumbers is EqualUnmodifiableListView) return _winningRegionOneNumbers;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_winningRegionOneNumbers);
}
@override final int winningRegionTwoNumber;
@override final int totalTickets;
@override final int totalPrizesAwarded;
@override final double totalPrizeAmount;
@override final DateTime createdAt;
@override final DateTime updatedAt;
@override final DateTime? deletedAt;
/// Create a copy of SnLotteryRecord
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnLotteryRecordCopyWith<_SnLotteryRecord> get copyWith => __$SnLotteryRecordCopyWithImpl<_SnLotteryRecord>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnLotteryRecordToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnLotteryRecord&&(identical(other.id, id) || other.id == id)&&(identical(other.drawDate, drawDate) || other.drawDate == drawDate)&&const DeepCollectionEquality().equals(other._winningRegionOneNumbers, _winningRegionOneNumbers)&&(identical(other.winningRegionTwoNumber, winningRegionTwoNumber) || other.winningRegionTwoNumber == winningRegionTwoNumber)&&(identical(other.totalTickets, totalTickets) || other.totalTickets == totalTickets)&&(identical(other.totalPrizesAwarded, totalPrizesAwarded) || other.totalPrizesAwarded == totalPrizesAwarded)&&(identical(other.totalPrizeAmount, totalPrizeAmount) || other.totalPrizeAmount == totalPrizeAmount)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,drawDate,const DeepCollectionEquality().hash(_winningRegionOneNumbers),winningRegionTwoNumber,totalTickets,totalPrizesAwarded,totalPrizeAmount,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'SnLotteryRecord(id: $id, drawDate: $drawDate, winningRegionOneNumbers: $winningRegionOneNumbers, winningRegionTwoNumber: $winningRegionTwoNumber, totalTickets: $totalTickets, totalPrizesAwarded: $totalPrizesAwarded, totalPrizeAmount: $totalPrizeAmount, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class _$SnLotteryRecordCopyWith<$Res> implements $SnLotteryRecordCopyWith<$Res> {
factory _$SnLotteryRecordCopyWith(_SnLotteryRecord value, $Res Function(_SnLotteryRecord) _then) = __$SnLotteryRecordCopyWithImpl;
@override @useResult
$Res call({
String id, DateTime drawDate, List<int> winningRegionOneNumbers, int winningRegionTwoNumber, int totalTickets, int totalPrizesAwarded, double totalPrizeAmount, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
});
}
/// @nodoc
class __$SnLotteryRecordCopyWithImpl<$Res>
implements _$SnLotteryRecordCopyWith<$Res> {
__$SnLotteryRecordCopyWithImpl(this._self, this._then);
final _SnLotteryRecord _self;
final $Res Function(_SnLotteryRecord) _then;
/// Create a copy of SnLotteryRecord
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? drawDate = null,Object? winningRegionOneNumbers = null,Object? winningRegionTwoNumber = null,Object? totalTickets = null,Object? totalPrizesAwarded = null,Object? totalPrizeAmount = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_SnLotteryRecord(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,drawDate: null == drawDate ? _self.drawDate : drawDate // ignore: cast_nullable_to_non_nullable
as DateTime,winningRegionOneNumbers: null == winningRegionOneNumbers ? _self._winningRegionOneNumbers : winningRegionOneNumbers // ignore: cast_nullable_to_non_nullable
as List<int>,winningRegionTwoNumber: null == winningRegionTwoNumber ? _self.winningRegionTwoNumber : winningRegionTwoNumber // ignore: cast_nullable_to_non_nullable
as int,totalTickets: null == totalTickets ? _self.totalTickets : totalTickets // ignore: cast_nullable_to_non_nullable
as int,totalPrizesAwarded: null == totalPrizesAwarded ? _self.totalPrizesAwarded : totalPrizesAwarded // ignore: cast_nullable_to_non_nullable
as int,totalPrizeAmount: null == totalPrizeAmount ? _self.totalPrizeAmount : totalPrizeAmount // ignore: cast_nullable_to_non_nullable
as double,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
}
// dart format on

View File

@@ -414,3 +414,88 @@ Map<String, dynamic> _$SnWalletFundRecipientToJson(
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};
_SnLotteryTicket _$SnLotteryTicketFromJson(Map<String, dynamic> json) =>
_SnLotteryTicket(
id: json['id'] as String,
accountId: json['account_id'] as String,
account:
json['account'] == null
? null
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
regionOneNumbers:
(json['region_one_numbers'] as List<dynamic>)
.map((e) => (e as num).toInt())
.toList(),
regionTwoNumber: (json['region_two_number'] as num).toInt(),
multiplier: (json['multiplier'] as num).toInt(),
drawStatus: (json['draw_status'] as num).toInt(),
drawDate:
json['draw_date'] == null
? null
: DateTime.parse(json['draw_date'] as String),
matchedRegionOneNumbers:
(json['matched_region_one_numbers'] as List<dynamic>?)
?.map((e) => (e as num).toInt())
.toList(),
matchedRegionTwoNumber:
(json['matched_region_two_number'] as num?)?.toInt(),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$SnLotteryTicketToJson(_SnLotteryTicket instance) =>
<String, dynamic>{
'id': instance.id,
'account_id': instance.accountId,
'account': instance.account?.toJson(),
'region_one_numbers': instance.regionOneNumbers,
'region_two_number': instance.regionTwoNumber,
'multiplier': instance.multiplier,
'draw_status': instance.drawStatus,
'draw_date': instance.drawDate?.toIso8601String(),
'matched_region_one_numbers': instance.matchedRegionOneNumbers,
'matched_region_two_number': instance.matchedRegionTwoNumber,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};
_SnLotteryRecord _$SnLotteryRecordFromJson(Map<String, dynamic> json) =>
_SnLotteryRecord(
id: json['id'] as String,
drawDate: DateTime.parse(json['draw_date'] as String),
winningRegionOneNumbers:
(json['winning_region_one_numbers'] as List<dynamic>)
.map((e) => (e as num).toInt())
.toList(),
winningRegionTwoNumber:
(json['winning_region_two_number'] as num).toInt(),
totalTickets: (json['total_tickets'] as num).toInt(),
totalPrizesAwarded: (json['total_prizes_awarded'] as num).toInt(),
totalPrizeAmount: (json['total_prize_amount'] as num).toDouble(),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$SnLotteryRecordToJson(_SnLotteryRecord instance) =>
<String, dynamic>{
'id': instance.id,
'draw_date': instance.drawDate.toIso8601String(),
'winning_region_one_numbers': instance.winningRegionOneNumbers,
'winning_region_two_number': instance.winningRegionTwoNumber,
'total_tickets': instance.totalTickets,
'total_prizes_awarded': instance.totalPrizesAwarded,
'total_prize_amount': instance.totalPrizeAmount,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};

View File

@@ -433,7 +433,7 @@ Future<void> setRemoteActivityStatus(
) async {
final apiClient = ref.read(apiClientProvider);
await apiClient.post(
'/id/accounts/me/statuses',
'/pass/accounts/me/statuses',
data: {
'is_invisible': false,
'is_not_disturb': false,
@@ -448,7 +448,7 @@ Future<void> setRemoteActivityStatus(
Future<void> unsetRemoteActivityStatus(Ref ref, String appId) async {
final apiClient = ref.read(apiClientProvider);
await apiClient.delete(
'/id/accounts/me/statuses',
'/pass/accounts/me/statuses',
queryParameters: {'app': appId},
);
}

View File

@@ -35,6 +35,7 @@ const kAppMessageDisplayStyle = 'app_message_display_style';
const kAppThemeMode = 'app_theme_mode';
const kMaterialYouToggleStoreKey = 'app_theme_material_you';
const kAppDisableAnimation = 'app_disable_animation';
const kAppFabPosition = 'app_fab_position';
const kFeaturedPostsCollapsedId =
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
@@ -98,6 +99,7 @@ sealed class AppSettings with _$AppSettings {
required String? themeMode,
required bool useMaterial3,
required bool disableAnimation,
required String fabPosition,
}) = _AppSettings;
}
@@ -125,6 +127,7 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
themeMode: prefs.getString(kAppThemeMode) ?? 'system',
useMaterial3: prefs.getBool(kMaterialYouToggleStoreKey) ?? true,
disableAnimation: prefs.getBool(kAppDisableAnimation) ?? false,
fabPosition: prefs.getString(kAppFabPosition) ?? 'center',
);
}
@@ -282,6 +285,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
prefs.setBool(kAppDisableAnimation, value);
state = state.copyWith(disableAnimation: value);
}
void setFabPosition(String value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setString(kAppFabPosition, value);
state = state.copyWith(fabPosition: value);
}
}
final updateInfoProvider =

View File

@@ -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 useMaterial3; bool get disableAnimation;
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get useMaterial3; bool get disableAnimation; String get fabPosition;
/// 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.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.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.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation));
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.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.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition));
}
@override
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation);
int get hashCode => Object.hashAll([runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation,fabPosition]);
@override
String toString() {
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation)';
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation, fabPosition: $fabPosition)';
}
@@ -321,7 +321,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
@useResult
$Res call({
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition
});
@@ -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? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,Object? disableAnimation = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,Object? disableAnimation = null,Object? fabPosition = null,}) {
return _then(_self.copyWith(
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
@@ -358,7 +358,8 @@ as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDispl
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
as String?,useMaterial3: null == useMaterial3 ? _self.useMaterial3 : useMaterial3 // ignore: cast_nullable_to_non_nullable
as bool,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
as bool,
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
as String,
));
}
/// Create a copy of AppSettings
@@ -452,10 +453,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _AppSettings() when $default != null:
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation);case _:
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation,_that.fabPosition);case _:
return orElse();
}
@@ -473,10 +474,10 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition) $default,) {final _that = this;
switch (_that) {
case _AppSettings():
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation);}
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation,_that.fabPosition);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -490,10 +491,10 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition)? $default,) {final _that = this;
switch (_that) {
case _AppSettings() when $default != null:
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation);case _:
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation,_that.fabPosition);case _:
return null;
}
@@ -505,7 +506,7 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
class _AppSettings implements AppSettings {
const _AppSettings({required this.autoTranslate, required this.dataSavingMode, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.useMaterial3, required this.disableAnimation});
const _AppSettings({required this.autoTranslate, required this.dataSavingMode, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.useMaterial3, required this.disableAnimation, required this.fabPosition});
@override final bool autoTranslate;
@@ -530,6 +531,7 @@ class _AppSettings implements AppSettings {
@override final String? themeMode;
@override final bool useMaterial3;
@override final bool disableAnimation;
@override final String fabPosition;
/// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values.
@@ -541,16 +543,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.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.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.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.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition));
}
@override
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation);
int get hashCode => Object.hashAll([runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation,fabPosition]);
@override
String toString() {
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation)';
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation, fabPosition: $fabPosition)';
}
@@ -561,7 +563,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
@override @useResult
$Res call({
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition
});
@@ -578,7 +580,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? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,Object? disableAnimation = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,Object? disableAnimation = null,Object? fabPosition = null,}) {
return _then(_AppSettings(
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
@@ -598,7 +600,8 @@ as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDispl
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
as String?,useMaterial3: null == useMaterial3 ? _self.useMaterial3 : useMaterial3 // ignore: cast_nullable_to_non_nullable
as bool,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
as bool,
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
as String,
));
}

View File

@@ -30,7 +30,7 @@ Map<String, dynamic> _$ThemeColorsToJson(_ThemeColors instance) =>
// **************************************************************************
String _$appSettingsNotifierHash() =>
r'10ebd893c39d24ae588a4c0bf4144ee4656465a4';
r'22b695f2023e3251db3296858acd701f7211d757';
/// See also [AppSettingsNotifier].
@ProviderFor(AppSettingsNotifier)

View File

@@ -44,7 +44,7 @@ Future<List<SnEventCalendarEntry>> eventCalendar(
) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get(
'/id/accounts/${query.uname ?? 'me'}/calendar',
'/pass/accounts/${query.uname ?? 'me'}/calendar',
queryParameters: {'year': query.year, 'month': query.month},
);
return resp.data

View File

@@ -6,7 +6,7 @@ part of 'event_calendar.dart';
// RiverpodGenerator
// **************************************************************************
String _$eventCalendarHash() => r'72232fc044ac3c99b855dca37ff2f06a64be0afb';
String _$eventCalendarHash() => r'3a33581c28bcd44bc5eb3abdb770171b4d275a5d';
/// Copied from Dart SDK
class _SystemHash {

View File

@@ -88,7 +88,7 @@ ThemeData createAppTheme(Brightness brightness, AppSettings settings) {
color: colorScheme.surfaceContainer.withOpacity(
settings.cardTransparency,
),
elevation: settings.cardTransparency <= 1 ? 0 : null,
elevation: settings.cardTransparency < 1 ? 0 : null,
),
pageTransitionsTheme: PageTransitionsTheme(
builders: {

View File

@@ -26,7 +26,7 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> {
}
try {
final client = _ref.read(apiClientProvider);
final response = await client.get('/id/accounts/me');
final response = await client.get('/pass/accounts/me');
final user = SnAccount.fromJson(response.data);
state = AsyncValue.data(user);

View File

@@ -37,6 +37,7 @@ import 'package:island/screens/chat/room.dart';
import 'package:island/screens/chat/room_detail.dart';
import 'package:island/screens/chat/call.dart';
import 'package:island/screens/chat/search_messages.dart';
import 'package:island/screens/thought/think.dart';
import 'package:island/screens/creators/hub.dart';
import 'package:island/screens/creators/posts/post_manage_list.dart';
import 'package:island/screens/creators/stickers/stickers.dart';
@@ -131,6 +132,11 @@ final routerProvider = Provider<GoRouter>((ref) {
return CallScreen(roomId: id);
},
),
GoRoute(
name: 'thought',
path: '/thought',
builder: (context, state) => const ThoughtScreen(),
),
GoRoute(
name: 'logs',
path: '/logs',

View File

@@ -203,7 +203,7 @@ class AccountScreen extends HookConsumerWidget {
],
).padding(horizontal: 16, vertical: 12),
onTap: () {
context.pushNamed('developerHub');
context.goNamed('developerHub');
},
),
).height(140),
@@ -383,7 +383,7 @@ class AccountScreen extends HookConsumerWidget {
onTap: () async {
final apiClient = ref.watch(apiClientProvider);
showLoadingModal(context);
await apiClient.delete('/id/accounts/me/sessions/current');
await apiClient.delete('/pass/accounts/me/sessions/current');
if (!context.mounted) return;
hideLoadingModal(context);
final userNotifier = ref.read(userInfoProvider.notifier);

View File

@@ -14,7 +14,7 @@ part 'credits.g.dart';
@riverpod
Future<double> socialCredits(Ref ref) async {
final client = ref.watch(apiClientProvider);
final response = await client.get('/id/accounts/me/credits');
final response = await client.get('/pass/accounts/me/credits');
if (response.statusCode != 200) {
throw Exception('Failed to load social credits');
}
@@ -39,7 +39,7 @@ class SocialCreditHistoryNotifier extends _$SocialCreditHistoryNotifier
final queryParams = {'offset': offset, 'take': _pageSize};
final response = await client.get(
'/id/accounts/me/credits/history',
'/pass/accounts/me/credits/history',
queryParameters: queryParams,
);
final total = int.parse(response.headers.value('X-Total') ?? '0');

View File

@@ -6,7 +6,7 @@ part of 'credits.dart';
// RiverpodGenerator
// **************************************************************************
String _$socialCreditsHash() => r'2599844e892127ee4d315caced5c10e4dbaea142';
String _$socialCreditsHash() => r'a0284583e94bc97285c689ac2bc018536932da69';
/// See also [socialCredits].
@ProviderFor(socialCredits)
@@ -25,7 +25,7 @@ final socialCreditsProvider = AutoDisposeFutureProvider<double>.internal(
// ignore: unused_element
typedef SocialCreditsRef = AutoDisposeFutureProviderRef<double>;
String _$socialCreditHistoryNotifierHash() =>
r'950db020754160f835c64cedf3fa2175e61e4d64';
r'3e87af246cc5dc72a1f3a87b81d1c87169bdfb5b';
/// See also [SocialCreditHistoryNotifier].
@ProviderFor(SocialCreditHistoryNotifier)

View File

@@ -34,7 +34,7 @@ class LevelingHistoryNotifier extends _$LevelingHistoryNotifier
final queryParams = {'offset': offset, 'take': _pageSize};
final response = await client.get(
'/id/accounts/me/leveling',
'/pass/accounts/me/leveling',
queryParameters: queryParams,
);
final total = int.parse(response.headers.value('X-Total') ?? '0');

View File

@@ -7,7 +7,7 @@ part of 'leveling.dart';
// **************************************************************************
String _$levelingHistoryNotifierHash() =>
r'e795f9b7911c9e50f15c095ea237cb0e87bf1e89';
r'de51012e1590ac46388b6f3f2050b21cb96698d1';
/// See also [LevelingHistoryNotifier].
@ProviderFor(LevelingHistoryNotifier)

View File

@@ -28,14 +28,14 @@ part 'account_settings.g.dart';
@riverpod
Future<List<SnAuthFactor>> authFactors(Ref ref) async {
final client = ref.read(apiClientProvider);
final res = await client.get('/id/accounts/me/factors');
final res = await client.get('/pass/accounts/me/factors');
return res.data.map<SnAuthFactor>((e) => SnAuthFactor.fromJson(e)).toList();
}
@riverpod
Future<List<SnContactMethod>> contactMethods(Ref ref) async {
final client = ref.read(apiClientProvider);
final resp = await client.get('/id/accounts/me/contacts');
final resp = await client.get('/pass/accounts/me/contacts');
return resp.data
.map<SnContactMethod>((e) => SnContactMethod.fromJson(e))
.toList();
@@ -44,7 +44,7 @@ Future<List<SnContactMethod>> contactMethods(Ref ref) async {
@riverpod
Future<List<SnAccountConnection>> accountConnections(Ref ref) async {
final client = ref.read(apiClientProvider);
final resp = await client.get('/id/accounts/me/connections');
final resp = await client.get('/pass/accounts/me/connections');
return resp.data
.map<SnAccountConnection>((e) => SnAccountConnection.fromJson(e))
.toList();
@@ -67,7 +67,7 @@ class AccountSettingsScreen extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.delete('/id/accounts/me');
await client.delete('/pass/accounts/me');
if (context.mounted) {
showSnackBar('accountDeletionSent'.tr());
}
@@ -93,7 +93,7 @@ class AccountSettingsScreen extends HookConsumerWidget {
final userInfo = ref.read(userInfoProvider);
final client = ref.read(apiClientProvider);
await client.post(
'/id/accounts/recovery/password',
'/pass/accounts/recovery/password',
data: {'account': userInfo.value!.name, 'captcha_token': captchaTk},
);
if (context.mounted) {

View File

@@ -6,7 +6,7 @@ part of 'account_settings.dart';
// RiverpodGenerator
// **************************************************************************
String _$authFactorsHash() => r'24fe2f7b375b019d87fc3b85cbedbe857f399c0f';
String _$authFactorsHash() => r'ed87d7dbd421fef0a5620416727c3dc598c97ef5';
/// See also [authFactors].
@ProviderFor(authFactors)
@@ -25,7 +25,7 @@ final authFactorsProvider =
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef AuthFactorsRef = AutoDisposeFutureProviderRef<List<SnAuthFactor>>;
String _$contactMethodsHash() => r'76a1a93f61c51c44b32b4821f5112d58406155f0';
String _$contactMethodsHash() => r'1d3d03e9ffbf36126236558ead22cb7d88bb9cb2';
/// See also [contactMethods].
@ProviderFor(contactMethods)
@@ -45,7 +45,7 @@ final contactMethodsProvider =
// ignore: unused_element
typedef ContactMethodsRef = AutoDisposeFutureProviderRef<List<SnContactMethod>>;
String _$accountConnectionsHash() =>
r'9f69e7f23e3e53c528d38b93d76f0c9efc9a83db';
r'33c10b98962ede6c428d4028c0d5f2f12ff0eb22';
/// See also [accountConnections].
@ProviderFor(accountConnections)

View File

@@ -87,7 +87,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
}
final client = ref.watch(apiClientProvider);
await client.patch(
'/id/accounts/me/profile',
'/pass/accounts/me/profile',
data: {'${position}_id': cloudFile.id},
);
final userNotifier = ref.read(userInfoProvider.notifier);
@@ -114,7 +114,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
await client.patch(
'/id/accounts/me',
'/pass/accounts/me',
data: {
'name': usernameController.text,
'nick': nicknameController.text,
@@ -194,7 +194,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
};
await client.patch(
'/id/accounts/me/profile',
'/pass/accounts/me/profile',
data: {
'bio': bioController.text,
'first_name': firstNameController.text,

View File

@@ -31,7 +31,7 @@ class AuthFactorSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.delete('/id/accounts/me/factors/${factor.id}');
await client.delete('/pass/accounts/me/factors/${factor.id}');
if (context.mounted) Navigator.pop(context, true);
} catch (err) {
showErrorAlert(err);
@@ -49,7 +49,7 @@ class AuthFactorSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.post('/id/accounts/me/factors/${factor.id}/disable');
await client.post('/pass/accounts/me/factors/${factor.id}/disable');
if (context.mounted) Navigator.pop(context, true);
} catch (err) {
showErrorAlert(err);
@@ -106,7 +106,7 @@ class AuthFactorSheet extends HookConsumerWidget {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.post(
'/id/accounts/me/factors/${factor.id}/enable',
'/pass/accounts/me/factors/${factor.id}/enable',
data: jsonEncode(password),
);
if (context.mounted) Navigator.pop(context, true);
@@ -193,7 +193,7 @@ class AuthFactorNewSheet extends HookConsumerWidget {
showLoadingModal(context);
final apiClient = ref.read(apiClientProvider);
final resp = await apiClient.post(
'/id/accounts/me/factors',
'/pass/accounts/me/factors',
data: {'type': factorType.value, 'secret': secretController.text},
);
final factor = SnAuthFactor.fromJson(resp.data);

View File

@@ -77,7 +77,7 @@ class AccountConnectionSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.delete('/id/accounts/me/connections/${connection.id}');
await client.delete('/pass/accounts/me/connections/${connection.id}');
if (context.mounted) Navigator.pop(context, true);
} catch (err) {
showErrorAlert(err);
@@ -175,7 +175,7 @@ class AccountConnectionNewSheet extends HookConsumerWidget {
if (context.mounted) showLoadingModal(context);
await client.post(
'/id/auth/connect/apple/mobile',
'/pass/auth/connect/apple/mobile',
data: {
'identity_token': credential.identityToken!,
'authorization_code': credential.authorizationCode,
@@ -200,7 +200,7 @@ class AccountConnectionNewSheet extends HookConsumerWidget {
final serverUrl = ref.watch(serverUrlProvider);
final accessToken = ref.watch(tokenProvider);
launchUrlString(
'$serverUrl/id/auth/login/${selectedProvider.value}?tk=${accessToken!.token}',
'$serverUrl/pass/auth/login/${selectedProvider.value}?tk=${accessToken!.token}',
);
} else {
await Navigator.of(context, rootNavigator: true).push(
@@ -345,7 +345,7 @@ class AccountConnectionsSheet extends HookConsumerWidget {
try {
final client = ref.read(apiClientProvider);
await client.delete(
'/id/accounts/me/connections/${connection.id}',
'/pass/accounts/me/connections/${connection.id}',
);
ref.invalidate(accountConnectionsProvider);
return true;

View File

@@ -25,7 +25,7 @@ class ContactMethodSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.delete('/id/accounts/me/contacts/${contact.id}');
await client.delete('/pass/accounts/me/contacts/${contact.id}');
if (context.mounted) Navigator.pop(context, true);
} catch (err) {
showErrorAlert(err);
@@ -38,7 +38,7 @@ class ContactMethodSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.post('/id/accounts/me/contacts/${contact.id}/verify');
await client.post('/pass/accounts/me/contacts/${contact.id}/verify');
if (context.mounted) {
showSnackBar('contactMethodVerificationSent'.tr());
}
@@ -53,7 +53,7 @@ class ContactMethodSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.post('/id/accounts/me/contacts/${contact.id}/primary');
await client.post('/pass/accounts/me/contacts/${contact.id}/primary');
if (context.mounted) Navigator.pop(context, true);
} catch (err) {
showErrorAlert(err);
@@ -66,7 +66,7 @@ class ContactMethodSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.post('/id/accounts/me/contacts/${contact.id}/public');
await client.post('/pass/accounts/me/contacts/${contact.id}/public');
if (context.mounted) Navigator.pop(context, true);
} catch (err) {
showErrorAlert(err);
@@ -79,7 +79,7 @@ class ContactMethodSheet extends HookConsumerWidget {
try {
showLoadingModal(context);
final client = ref.read(apiClientProvider);
await client.delete('/id/accounts/me/contacts/${contact.id}/public');
await client.delete('/pass/accounts/me/contacts/${contact.id}/public');
if (context.mounted) Navigator.pop(context, true);
} catch (err) {
showErrorAlert(err);
@@ -221,7 +221,7 @@ class ContactMethodNewSheet extends HookConsumerWidget {
showLoadingModal(context);
final apiClient = ref.read(apiClientProvider);
await apiClient.post(
'/id/accounts/me/contacts',
'/pass/accounts/me/contacts',
data: {'type': contactType.value, 'content': contentController.text},
);
if (context.mounted) {

View File

@@ -561,14 +561,14 @@ Future<SnAccount> account(Ref ref, String uname) async {
}
}
final apiClient = ref.watch(apiClientProvider);
final resp = await apiClient.get("/id/accounts/$uname");
final resp = await apiClient.get("/pass/accounts/$uname");
return SnAccount.fromJson(resp.data);
}
@riverpod
Future<List<SnAccountBadge>> accountBadges(Ref ref, String uname) async {
final apiClient = ref.watch(apiClientProvider);
final resp = await apiClient.get("/id/accounts/$uname/badges");
final resp = await apiClient.get("/pass/accounts/$uname/badges");
return List<SnAccountBadge>.from(
resp.data.map((x) => SnAccountBadge.fromJson(x)),
);
@@ -617,7 +617,7 @@ Future<SnRelationship?> accountRelationship(Ref ref, String uname) async {
final account = await ref.watch(accountProvider(uname).future);
final apiClient = ref.watch(apiClientProvider);
try {
final resp = await apiClient.get("/id/relationships/${account.id}");
final resp = await apiClient.get("/pass/relationships/${account.id}");
return SnRelationship.fromJson(resp.data);
} catch (err) {
if (err is DioException && err.response?.statusCode == 404) {
@@ -690,7 +690,7 @@ class AccountProfileScreen extends HookConsumerWidget {
showLoadingModal(context);
try {
final client = ref.watch(apiClientProvider);
await client.post('/id/relationships/${account.value!.id}/friends');
await client.post('/pass/relationships/${account.value!.id}/friends');
ref.invalidate(accountRelationshipProvider(name));
} catch (err) {
showErrorAlert(err);
@@ -704,9 +704,9 @@ class AccountProfileScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
if (accountRelationship.value == null) {
await client.post('/id/relationships/${account.value!.id}/block');
await client.post('/pass/relationships/${account.value!.id}/block');
} else {
await client.delete('/id/relationships/${account.value!.id}/block');
await client.delete('/pass/relationships/${account.value!.id}/block');
}
ref.invalidate(accountRelationshipProvider(name));
} catch (err) {

View File

@@ -6,7 +6,7 @@ part of 'profile.dart';
// RiverpodGenerator
// **************************************************************************
String _$accountHash() => r'ce7264a04f69e32a5cb07bc10ca5fa47ae1fddaa';
String _$accountHash() => r'5e2b7bd59151b4638a5561f495537c259f767123';
/// Copied from Dart SDK
class _SystemHash {
@@ -145,7 +145,7 @@ class _AccountProviderElement
String get uname => (origin as AccountProvider).uname;
}
String _$accountBadgesHash() => r'1de05e122c23ff2c6ac6d318977165761e2ad177';
String _$accountBadgesHash() => r'68db63f49827020beecbdbf20529520d0cd14a7d';
/// See also [accountBadges].
@ProviderFor(accountBadges)
@@ -517,7 +517,7 @@ class _AccountDirectChatProviderElement
}
String _$accountRelationshipHash() =>
r'9a3a4e8c6c6706f73df95feccb86736fcad33f30';
r'319f743261b113a1d3c6a397d48d13c858312669';
/// See also [accountRelationship].
@ProviderFor(accountRelationship)

View File

@@ -21,7 +21,7 @@ part 'relationship.g.dart';
@riverpod
Future<List<SnRelationship>> sentFriendRequest(Ref ref) async {
final client = ref.read(apiClientProvider);
final resp = await client.get('/id/relationships/requests');
final resp = await client.get('/pass/relationships/requests');
return resp.data
.map((e) => SnRelationship.fromJson(e))
.cast<SnRelationship>()
@@ -43,7 +43,7 @@ class RelationshipListNotifier extends _$RelationshipListNotifier
final take = 20;
final response = await client.get(
'/id/relationships',
'/pass/relationships',
queryParameters: {'offset': offset, 'take': take},
);
@@ -226,7 +226,7 @@ class RelationshipScreen extends HookConsumerWidget {
if (result == null) return;
final client = ref.read(apiClientProvider);
await client.post('/id/relationships/${result.id}/friends');
await client.post('/pass/relationships/${result.id}/friends');
ref.invalidate(sentFriendRequestProvider);
}
@@ -240,7 +240,7 @@ class RelationshipScreen extends HookConsumerWidget {
submitting.value = true;
final client = ref.read(apiClientProvider);
await client.post(
'/id/relationships/${relationship.accountId}/friends/${isAccept ? 'accept' : 'decline'}',
'/pass/relationships/${relationship.accountId}/friends/${isAccept ? 'accept' : 'decline'}',
);
relationshipNotifier.forceRefresh();
if (!context.mounted) return;
@@ -267,7 +267,7 @@ class RelationshipScreen extends HookConsumerWidget {
) async {
final client = ref.read(apiClientProvider);
await client.patch(
'/id/relationships/${relationship.accountId}',
'/pass/relationships/${relationship.accountId}',
data: {'status': newStatus},
);
relationshipNotifier.forceRefresh();
@@ -350,7 +350,7 @@ class _SentFriendRequestsSheet extends HookConsumerWidget {
Future<void> cancelRequest(SnRelationship request) async {
try {
final client = ref.read(apiClientProvider);
await client.delete('/id/relationships/${request.relatedId}/friends');
await client.delete('/pass/relationships/${request.relatedId}/friends');
ref.invalidate(sentFriendRequestProvider);
} catch (err) {
showErrorAlert(err);

View File

@@ -6,7 +6,7 @@ part of 'relationship.dart';
// RiverpodGenerator
// **************************************************************************
String _$sentFriendRequestHash() => r'dc02ace6cb755a01ab862c9fcff3b26de7f946cb';
String _$sentFriendRequestHash() => r'0c52813eb6f86c05f6e0b1e4e840d0d9c350aa9e';
/// See also [sentFriendRequest].
@ProviderFor(sentFriendRequest)
@@ -27,7 +27,7 @@ final sentFriendRequestProvider =
typedef SentFriendRequestRef =
AutoDisposeFutureProviderRef<List<SnRelationship>>;
String _$relationshipListNotifierHash() =>
r'0a134ce69489a4f2002d2223853855b6f22e4e9f';
r'fc46920256f7c48445c00652165e879890f2c9a3';
/// See also [RelationshipListNotifier].
@ProviderFor(RelationshipListNotifier)

View File

@@ -49,7 +49,7 @@ class CreateAccountScreen extends HookConsumerWidget {
showLoadingModal(context);
final client = ref.watch(apiClientProvider);
await client.post(
'/id/accounts',
'/pass/accounts',
data: {
'name': usernameController.text,
'nick': nicknameController.text,

View File

@@ -175,7 +175,7 @@ class _LoginCheckScreen extends HookConsumerWidget {
// Get token if challenge is completed
final client = ref.watch(apiClientProvider);
final tokenResp = await client.post(
'/id/auth/token',
'/pass/auth/token',
data: {
'grant_type': 'authorization_code',
'code': code ?? challenge!.id,
@@ -241,7 +241,7 @@ class _LoginCheckScreen extends HookConsumerWidget {
// Pass challenge
final client = ref.watch(apiClientProvider);
final resp = await client.patch(
'/id/auth/challenge/${challenge!.id}',
'/pass/auth/challenge/${challenge!.id}',
data: {'factor_id': factor!.id, 'password': pwd},
);
final result = SnAuthChallenge.fromJson(resp.data);
@@ -388,7 +388,7 @@ class _LoginPickerScreen extends HookConsumerWidget {
try {
await client.post(
'/id/auth/challenge/${challenge!.id}/factors/${factorPicked.value!.id}',
'/pass/auth/challenge/${challenge!.id}/factors/${factorPicked.value!.id}',
data:
hintController.text.isNotEmpty
? jsonEncode(hintController.text)
@@ -531,7 +531,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
await client.post(
'/id/accounts/recovery/password',
'/pass/accounts/recovery/password',
data: {'account': uname, 'captcha_token': captchaTk},
);
showInfoAlert('loginResetPasswordSent'.tr(), 'done'.tr());
@@ -549,7 +549,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
final resp = await client.post(
'/id/auth/challenge',
'/pass/auth/challenge',
data: {
'account': uname,
'device_id': await getUdid(),
@@ -570,7 +570,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
final result = SnAuthChallenge.fromJson(resp.data);
onChallenge(result);
final factorResp = await client.get(
'/id/auth/challenge/${result.id}/factors',
'/pass/auth/challenge/${result.id}/factors',
);
onFactor(
List<SnAuthFactor>.from(
@@ -599,7 +599,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
if (context.mounted) showLoadingModal(context);
final resp = await client.post(
'/id/auth/login/apple/mobile',
'/pass/auth/login/apple/mobile',
data: {
'identity_token': credential.identityToken!,
'authorization_code': credential.authorizationCode,
@@ -611,7 +611,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
final challenge = SnAuthChallenge.fromJson(resp.data);
onChallenge(challenge);
final factorResp = await client.get(
'/id/auth/challenge/${challenge.id}/factors',
'/pass/auth/challenge/${challenge.id}/factors',
);
onFactor(
List<SnAuthFactor>.from(
@@ -636,11 +636,11 @@ class _LoginLookupScreen extends HookConsumerWidget {
final client = ref.watch(apiClientProvider);
try {
final resp = await client.get('/id/auth/challenge/$challengeId');
final resp = await client.get('/pass/auth/challenge/$challengeId');
final challenge = SnAuthChallenge.fromJson(resp.data);
onChallenge(challenge);
final factorResp = await client.get(
'/id/auth/challenge/${challenge.id}/factors',
'/pass/auth/challenge/${challenge.id}/factors',
);
onFactor(
List<SnAuthFactor>.from(

View File

@@ -80,7 +80,9 @@ class _OidcScreenState extends ConsumerState<OidcScreen> {
: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
),
initialUrlRequest: URLRequest(
url: WebUri('$serverUrl/id/auth/login/${widget.provider}'),
url: WebUri(
'$serverUrl/pass/auth/login/${widget.provider}',
),
headers: {
if (token?.token.isNotEmpty ?? false)
'Authorization': 'AtField ${token!.token}',

View File

@@ -10,12 +10,13 @@ import 'package:island/pods/chat/call.dart';
import 'package:island/pods/chat/chat_summary.dart';
import 'package:island/pods/network.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/content/cloud_files.dart';
import 'package:island/widgets/content/sheet.dart';
import 'package:island/widgets/navigation/fab_menu.dart';
import 'package:island/widgets/response.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:relative_time/relative_time.dart';
@@ -238,10 +239,17 @@ class ChatListBodyWidget extends HookConsumerWidget {
room: item,
isDirect: item.type == 1,
onTap: () {
context.pushNamed(
'chatRoom',
pathParameters: {'id': item.id},
);
if (isWideScreen(context)) {
context.replaceNamed(
'chatRoom',
pathParameters: {'id': item.id},
);
} else {
context.pushNamed(
'chatRoom',
pathParameters: {'id': item.id},
);
}
},
);
},
@@ -326,28 +334,30 @@ class ChatListScreen extends HookConsumerWidget {
tabController.addListener(() {
selectedTab.value = tabController.index;
});
return null;
// Listen for chat rooms refresh events
final subscription = eventBus.on<ChatRoomsRefreshEvent>().listen((event) {
ref.invalidate(chatroomsJoinedProvider);
});
return () {
subscription.cancel();
};
}, [tabController]);
Future<void> createDirectMessage() 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(
'/sphere/chat/direct',
data: {'related_user_id': result.id},
);
ref.invalidate(chatroomsJoinedProvider);
} catch (err) {
showErrorAlert(err);
}
}
useEffect(() {
// Set FAB type to chat
final fabMenuNotifier = ref.read(fabMenuTypeProvider.notifier);
WidgetsBinding.instance.addPostFrameCallback((_) {
fabMenuNotifier.state = FabMenuType.chat;
});
return () {
// Clean up: reset FAB type to main
WidgetsBinding.instance.addPostFrameCallback((_) {
fabMenuNotifier.state = FabMenuType.main;
});
};
}, []);
if (isAside) {
return Card(
@@ -484,43 +494,6 @@ class ChatListScreen extends HookConsumerWidget {
const Gap(8),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showModalBottomSheet(
context: context,
useRootNavigator: true,
builder:
(context) => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ListTile(
title: const Text('createChatRoom').tr(),
leading: const Icon(Symbols.add),
onTap: () {
Navigator.pop(context);
context.pushNamed('chatNew').then((value) {
if (value != null) {
ref.invalidate(chatroomsJoinedProvider);
}
});
},
),
ListTile(
title: const Text('createDirectMessage').tr(),
leading: const Icon(Symbols.person),
onTap: () {
Navigator.pop(context);
createDirectMessage();
},
),
Gap(MediaQuery.of(context).padding.bottom + 16),
],
),
);
},
child: const Icon(Symbols.add),
),
body: ChatListBodyWidget(
isFloating: false,
tabController: tabController,

View File

@@ -34,6 +34,7 @@ import "package:island/widgets/chat/call_button.dart";
import "package:island/widgets/chat/chat_input.dart";
import "package:island/widgets/chat/chat_link_attachments.dart";
import "package:island/widgets/chat/public_room_preview.dart";
import "package:island/screens/thought/think_sheet.dart";
class ChatRoomScreen extends HookConsumerWidget {
final String id;
@@ -145,6 +146,10 @@ class ChatRoomScreen extends HookConsumerWidget {
final attachments = useState<List<UniversalFile>>([]);
final attachmentProgress = useState<Map<String, Map<int, double>>>({});
// Selection mode state
final isSelectionMode = useState<bool>(false);
final selectedMessages = useState<Set<String>>({});
var isLoading = false;
var isScrollingToMessage = false; // Flag to prevent scroll conflicts
@@ -284,6 +289,53 @@ class ChatRoomScreen extends HookConsumerWidget {
return () => messageController.removeListener(onTextChange);
}, [messageController]);
// Selection functions
void toggleSelectionMode() {
isSelectionMode.value = !isSelectionMode.value;
if (!isSelectionMode.value) {
selectedMessages.value = {};
}
}
void toggleMessageSelection(String messageId) {
final newSelection = Set<String>.from(selectedMessages.value);
if (newSelection.contains(messageId)) {
newSelection.remove(messageId);
} else {
newSelection.add(messageId);
}
selectedMessages.value = newSelection;
}
void openThinkingSheet() {
if (selectedMessages.value.isEmpty) return;
// Convert selected message IDs to message data
final selectedMessageData =
messages.valueOrNull
?.where((msg) => selectedMessages.value.contains(msg.id))
.map(
(msg) => {
'id': msg.id,
'content': msg.content,
'senderId': msg.senderId,
'createdAt': msg.createdAt.toIso8601String(),
'attachments': msg.attachments,
},
)
.toList() ??
[];
ThoughtSheet.show(
context,
attachedMessages: selectedMessageData,
attachedPosts: [], // Could be extended to include posts
);
// Exit selection mode after opening
toggleSelectionMode();
}
final compactHeader = isWideScreen(context);
Widget onlineIndicator() => Row(
@@ -571,42 +623,106 @@ class ChatRoomScreen extends HookConsumerWidget {
final messageWidget = chatIdentity.when(
skipError: true,
data:
(identity) => MessageItem(
key: settings.disableAnimation ? key : null,
message: message,
isCurrentUser: identity?.id == message.senderId,
onAction: (action) {
switch (action) {
case MessageItemAction.delete:
messagesNotifier.deleteMessage(message.id);
case MessageItemAction.edit:
messageEditingTo.value = message.toRemoteMessage();
messageController.text =
messageEditingTo.value?.content ?? '';
attachments.value =
messageEditingTo.value!.attachments
.map((e) => UniversalFile.fromAttachment(e))
.toList();
case MessageItemAction.forward:
messageForwardingTo.value = message.toRemoteMessage();
case MessageItemAction.reply:
messageReplyingTo.value = message.toRemoteMessage();
case MessageItemAction.resend:
messagesNotifier.retryMessage(message.id);
(identity) => GestureDetector(
onLongPress: () {
if (!isSelectionMode.value) {
toggleSelectionMode();
toggleMessageSelection(message.id);
}
},
onJump: (messageId) {
scrollToMessage(
messageId: messageId,
messageList: messageList,
messagesNotifier: messagesNotifier,
listController: listController,
scrollController: scrollController,
ref: ref,
);
onTap: () {
if (isSelectionMode.value) {
toggleMessageSelection(message.id);
}
},
progress: attachmentProgress.value[message.id],
showAvatar: isLastInGroup,
child: Container(
color:
selectedMessages.value.contains(message.id)
? Theme.of(
context,
).colorScheme.primaryContainer.withOpacity(0.3)
: null,
child: Stack(
children: [
MessageItem(
key: settings.disableAnimation ? key : null,
message: message,
isCurrentUser: identity?.id == message.senderId,
onAction:
isSelectionMode.value
? null
: (action) {
switch (action) {
case MessageItemAction.delete:
messagesNotifier.deleteMessage(
message.id,
);
case MessageItemAction.edit:
messageEditingTo.value =
message.toRemoteMessage();
messageController.text =
messageEditingTo.value?.content ?? '';
attachments.value =
messageEditingTo.value!.attachments
.map(
(e) =>
UniversalFile.fromAttachment(
e,
),
)
.toList();
case MessageItemAction.forward:
messageForwardingTo.value =
message.toRemoteMessage();
case MessageItemAction.reply:
messageReplyingTo.value =
message.toRemoteMessage();
case MessageItemAction.resend:
messagesNotifier.retryMessage(message.id);
}
},
onJump: (messageId) {
scrollToMessage(
messageId: messageId,
messageList: messageList,
messagesNotifier: messagesNotifier,
listController: listController,
scrollController: scrollController,
ref: ref,
);
},
progress: attachmentProgress.value[message.id],
showAvatar: isLastInGroup,
isSelectionMode: isSelectionMode.value,
isSelected: selectedMessages.value.contains(message.id),
onToggleSelection: toggleMessageSelection,
onEnterSelectionMode: () {
if (!isSelectionMode.value) {
toggleSelectionMode();
}
},
),
if (selectedMessages.value.contains(message.id))
Positioned(
top: 8,
right: 8,
child: Container(
width: 16,
height: 16,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
shape: BoxShape.circle,
),
child: Icon(
Icons.check,
size: 12,
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
],
),
),
),
loading:
() => MessageItem(
@@ -756,71 +872,73 @@ class ChatRoomScreen extends HookConsumerWidget {
),
),
),
chatRoom.when(
data:
(room) => Column(
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;
},
messageEditingTo: messageEditingTo.value,
messageReplyingTo: messageReplyingTo.value,
messageForwardingTo: messageForwardingTo.value,
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),
],
),
error: (_, _) => const SizedBox.shrink(),
loading: () => const SizedBox.shrink(),
),
if (!isSelectionMode.value)
chatRoom.when(
data:
(room) => Column(
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;
},
messageEditingTo: messageEditingTo.value,
messageReplyingTo: messageReplyingTo.value,
messageForwardingTo: messageForwardingTo.value,
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),
],
),
error: (_, _) => const SizedBox.shrink(),
loading: () => const SizedBox.shrink(),
),
],
),
),
@@ -859,6 +977,43 @@ class ChatRoomScreen extends HookConsumerWidget {
),
),
),
// Selection mode toolbar
if (isSelectionMode.value)
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
color: Theme.of(context).colorScheme.surface,
padding: EdgeInsets.only(
left: 16,
right: 16,
top: 8,
bottom: MediaQuery.of(context).padding.bottom + 8,
),
child: Row(
children: [
IconButton(
icon: const Icon(Icons.close),
onPressed: toggleSelectionMode,
tooltip: 'Cancel selection',
),
const SizedBox(width: 8),
Text(
'${selectedMessages.value.length} selected',
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
if (selectedMessages.value.isNotEmpty)
FilledButton.icon(
onPressed: openThinkingSheet,
icon: Icon(Symbols.smart_toy),
label: const Text('AI Think'),
),
],
),
),
),
],
),
);

View File

@@ -522,7 +522,7 @@ class CreatorHubScreen extends HookConsumerWidget {
return AppScaffold(
isNoBackground: false,
appBar: AppBar(
leading: const PageBackButton(),
leading: const PageBackButton(backTo: '/account'),
title: Text('creatorHub').tr(),
actions: [
if (!isWideScreen(context))

View File

@@ -198,7 +198,7 @@ class StickerPackDetailContent extends HookConsumerWidget {
),
),
child: CloudImageWidget(
fileId: sticker.imageId,
fileId: sticker.image.id,
fit: BoxFit.contain,
),
),
@@ -318,7 +318,7 @@ class StickerForm extends HookConsumerWidget {
final formKey = useMemoized(() => GlobalKey<FormState>(), []);
final image = useState<String?>(id == null ? '' : sticker.value?.imageId);
final image = useState<String?>(id == null ? '' : sticker.value?.image.id);
final imageController = useTextEditingController(text: image.value);
final slugController = useTextEditingController(
text: id == null ? '' : sticker.value?.slug,
@@ -326,8 +326,8 @@ class StickerForm extends HookConsumerWidget {
useEffect(() {
if (sticker.value != null) {
image.value = sticker.value!.imageId;
imageController.text = sticker.value!.imageId;
image.value = sticker.value!.image.id;
imageController.text = sticker.value!.image.id;
slugController.text = sticker.value!.slug;
}
return null;

View File

@@ -181,7 +181,7 @@ class _ConsoleAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
return AppBar(
leading: const PageBackButton(),
leading: const PageBackButton(backTo: '/account'),
title: Text('developerHub').tr(),
actions: [
if (currentProject != null)

View File

@@ -19,7 +19,6 @@ import 'package:island/widgets/check_in.dart';
import 'package:island/widgets/post/post_featured.dart';
import 'package:island/widgets/post/post_item.dart';
import 'package:island/widgets/post/compose_card.dart';
import 'package:island/widgets/post/compose_dialog.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
@@ -91,10 +90,6 @@ class ExploreScreen extends HookConsumerWidget {
return () => tabController.removeListener(listener);
}, [tabController]);
final activitiesNotifier = ref.watch(
activityListNotifierProvider(currentFilter.value).notifier,
);
final now = DateTime.now();
final query = useState(
@@ -211,29 +206,11 @@ class ExploreScreen extends HookConsumerWidget {
).padding(horizontal: 8),
);
final appBar = isWide ? null : _buildAppBar(tabController, context);
return AppScaffold(
isNoBackground: false,
floatingActionButton:
isWide
? null
: InkWell(
onLongPress: () async {
final result = await PostComposeDialog.show(context);
if (result != null) {
activitiesNotifier.forceRefresh();
}
},
child: FloatingActionButton(
heroTag: Key("explore-page-fab"),
onPressed: () async {
final result = await PostComposeDialog.show(context);
if (result != null) {
activitiesNotifier.forceRefresh();
}
},
child: const Icon(Symbols.edit),
),
),
appBar: appBar,
body:
isWide
? _buildWideBody(
@@ -247,7 +224,7 @@ class ExploreScreen extends HookConsumerWidget {
selectedDay,
currentFilter.value,
)
: _buildNarrowBody(context, ref, filterBar, currentFilter.value),
: _buildNarrowBody(context, ref, currentFilter.value),
);
}
@@ -334,11 +311,7 @@ class ExploreScreen extends HookConsumerWidget {
margin: EdgeInsets.zero,
),
PostFeaturedList(),
PostComposeCard(
onSubmit: () {
activitiesNotifier.forceRefresh();
},
),
const PostComposeCard(),
],
),
),
@@ -367,10 +340,125 @@ class ExploreScreen extends HookConsumerWidget {
).padding(horizontal: 12);
}
PreferredSizeWidget _buildAppBar(
TabController tabController,
BuildContext context,
) {
final foregroundColor = Theme.of(context).appBarTheme.foregroundColor;
return AppBar(
toolbarHeight: 48 + 4,
flexibleSpace: Container(
height: 48,
margin: EdgeInsets.only(
left: 8,
right: 8,
top: 4 + MediaQuery.of(context).padding.top,
),
child: Row(
children: [
Expanded(
child: TabBar(
controller: tabController,
tabAlignment: TabAlignment.start,
isScrollable: true,
dividerColor: Colors.transparent,
tabs: [
Tab(
icon: Tooltip(
message: 'explore'.tr(),
child: Icon(Symbols.explore, color: foregroundColor),
),
),
Tab(
icon: Tooltip(
message: 'exploreFilterSubscriptions'.tr(),
child: Icon(
Symbols.subscriptions,
color: foregroundColor,
),
),
),
Tab(
icon: Tooltip(
message: 'exploreFilterFriends'.tr(),
child: Icon(Symbols.people, color: foregroundColor),
),
),
],
),
),
IconButton(
onPressed: () {
context.pushNamed('articles');
},
icon: Icon(Symbols.auto_stories, color: foregroundColor),
tooltip: 'webArticlesStand'.tr(),
),
PopupMenuButton(
itemBuilder:
(context) => [
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.category),
const Gap(12),
Text('categories').tr(),
],
),
onTap: () {
context.pushNamed('postCategories');
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.label),
const Gap(12),
Text('tags').tr(),
],
),
onTap: () {
context.pushNamed('postTags');
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.shuffle),
const Gap(12),
Text('postShuffle').tr(),
],
),
onTap: () {
context.pushNamed('postShuffle');
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.search),
const Gap(12),
Text('search').tr(),
],
),
onTap: () {
context.pushNamed('postSearch');
},
),
],
icon: Icon(Symbols.action_key, color: foregroundColor),
tooltip: 'search'.tr(),
),
],
),
),
);
}
Widget _buildNarrowBody(
BuildContext context,
WidgetRef ref,
Widget filterBar,
String? currentFilter,
) {
final user = ref.watch(userInfoProvider);
@@ -384,45 +472,39 @@ class ExploreScreen extends HookConsumerWidget {
final bodyView = _buildActivityList(context, ref, currentFilter);
return Column(
spacing: 8,
children: [
filterBar.padding(horizontal: 8, top: 8),
Expanded(
child: ExtendedRefreshIndicator(
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: CustomScrollView(
slivers: [
if (user.value != null)
SliverToBoxAdapter(
child: CheckInWidget(
margin: const EdgeInsets.only(bottom: 8),
),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: PostFeaturedList(),
),
return Expanded(
child: ExtendedRefreshIndicator(
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: CustomScrollView(
slivers: [
if (user.value != null)
SliverToBoxAdapter(
child: CheckInWidget(
margin: const EdgeInsets.only(bottom: 8, top: 8),
),
if (notificationCount.value != null &&
notificationCount.value! > 0)
SliverToBoxAdapter(
child: notificationIndicatorWidget(
context,
count: notificationCount.value ?? 0,
margin: const EdgeInsets.only(bottom: 8),
),
),
bodyView,
],
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: PostFeaturedList(),
),
),
).padding(horizontal: 8),
if (notificationCount.value != null &&
notificationCount.value! > 0)
SliverToBoxAdapter(
child: notificationIndicatorWidget(
context,
count: notificationCount.value ?? 0,
margin: const EdgeInsets.only(bottom: 8),
),
),
bodyView,
],
),
),
],
).padding(horizontal: 8),
),
);
}
}

829
lib/screens/lottery.dart Normal file
View File

@@ -0,0 +1,829 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/wallet.dart';
import 'package:island/pods/network.dart';
import 'package:island/screens/wallet.dart';
import 'package:island/services/time.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/content/sheet.dart';
import 'package:island/widgets/payment/payment_overlay.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart';
part 'lottery.g.dart';
@riverpod
Future<List<SnLotteryTicket>> lotteryTickets(
Ref ref, {
int offset = 0,
int take = 20,
}) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/pass/lotteries?offset=$offset&take=$take');
return (resp.data as List).map((e) => SnLotteryTicket.fromJson(e)).toList();
}
@riverpod
Future<List<SnLotteryRecord>> lotteryRecords(
Ref ref, {
int offset = 0,
int take = 20,
}) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get(
'/pass/lotteries/records?offset=$offset&take=$take',
);
return (resp.data as List).map((e) => SnLotteryRecord.fromJson(e)).toList();
}
class LotteryTab extends StatelessWidget {
const LotteryTab({super.key});
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Column(
children: [
TabBar(
tabs: [Tab(text: 'myTickets'.tr()), Tab(text: 'drawHistory'.tr())],
),
Expanded(
child: TabBarView(
children: [LotteryTicketsList(), LotteryRecordsList()],
),
),
],
),
);
}
}
class LotteryTicketsList extends HookConsumerWidget {
const LotteryTicketsList({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final tickets = ref.watch(lotteryTicketsProvider());
return tickets.when(
data: (ticketsList) {
if (ticketsList.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Symbols.casino,
size: 48,
color: Theme.of(context).colorScheme.outline,
),
const Gap(16),
Text(
'noLotteryTickets'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
const Gap(8),
Text(
'buyYourFirstTicket'.tr(),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
textAlign: TextAlign.center,
),
const Gap(16),
FilledButton.icon(
onPressed: () => _showLotteryPurchaseSheet(context, ref),
icon: const Icon(Symbols.add),
label: Text('buyTicket'.tr()),
),
],
),
);
}
return Column(
children: [
Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: ticketsList.length,
itemBuilder: (context, index) {
final ticket = ticketsList[index];
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Symbols.confirmation_number,
color: Theme.of(context).colorScheme.primary,
),
const Gap(8),
Expanded(
child: Text(ticket.createdAt.formatSystem()),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: _getLotteryStatusColor(
context,
ticket.drawStatus,
).withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Text(
_getLotteryStatusText(ticket.drawStatus),
style: TextStyle(
color: _getLotteryStatusColor(
context,
ticket.drawStatus,
),
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
],
),
const Gap(8),
_buildTicketNumbersDisplay(context, ticket),
const Gap(8),
Row(
spacing: 6,
children: [
const Icon(Symbols.asterisk, size: 18),
Text('multiplier').tr().fontSize(13),
Text(
'·',
).fontWeight(FontWeight.w900).fontSize(13),
Text(
'${ticket.multiplier}x',
style: Theme.of(context).textTheme.bodyMedium,
).fontSize(13),
],
).opacity(0.75),
],
),
),
);
},
),
),
Padding(
padding: const EdgeInsets.all(16),
child: FilledButton.icon(
onPressed: () => _showLotteryPurchaseSheet(context, ref),
icon: const Icon(Symbols.add),
label: Text('buyTicket'.tr()),
style: FilledButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
),
),
],
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')),
);
}
Future<void> _showLotteryPurchaseSheet(
BuildContext context,
WidgetRef ref,
) async {
final result = await showModalBottomSheet<Map<String, dynamic>>(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) => const LotteryPurchaseSheet(),
);
if (result != null && context.mounted) {
await _handleLotteryPurchase(context, ref, result);
}
}
Future<void> _handleLotteryPurchase(
BuildContext context,
WidgetRef ref,
Map<String, dynamic> purchaseData,
) async {
final client = ref.read(apiClientProvider);
try {
showLoadingModal(context);
// The lottery API creates the order for us
final orderResponse = await client.post(
'/pass/lotteries',
data: purchaseData,
);
if (context.mounted) hideLoadingModal(context);
final order = SnWalletOrder.fromJson(orderResponse.data);
// Show payment overlay
if (context.mounted) {
final completedOrder = await PaymentOverlay.show(
context: context,
order: order,
);
if (completedOrder != null) {
// Payment successful, refresh data
ref.invalidate(lotteryTicketsProvider);
ref.invalidate(walletCurrentProvider);
if (context.mounted) {
showSnackBar('ticketPurchasedSuccessfully'.tr());
}
}
}
} catch (err) {
if (context.mounted) hideLoadingModal(context);
showErrorAlert(err);
}
}
String _getLotteryStatusText(int status) {
switch (status) {
case 0:
return 'pending'.tr();
case 1:
return 'drawn'.tr();
case 2:
return 'won'.tr();
case 3:
return 'lost'.tr();
default:
return 'unknown'.tr();
}
}
Color _getLotteryStatusColor(BuildContext context, int status) {
switch (status) {
case 0:
return Colors.blue;
case 1:
return Colors.orange;
case 2:
return Colors.green;
case 3:
return Colors.red;
default:
return Theme.of(context).colorScheme.primary;
}
}
Widget _buildTicketNumbersDisplay(
BuildContext context,
SnLotteryTicket ticket,
) {
final numbers = <Widget>[];
// Check if any numbers matched
bool hasAnyMatch =
ticket.matchedRegionOneNumbers != null &&
ticket.matchedRegionOneNumbers!.isNotEmpty;
// Add region one numbers
for (final number in ticket.regionOneNumbers) {
final isMatched =
ticket.matchedRegionOneNumbers?.contains(number) ?? false;
if (isMatched) hasAnyMatch = true;
numbers.add(
_buildNumberWidget(
context,
number,
isMatched: isMatched,
allUnmatched: !hasAnyMatch && ticket.drawStatus >= 1,
),
);
}
// Add region two number
final isSpecialMatched =
ticket.matchedRegionTwoNumber == ticket.regionTwoNumber;
if (isSpecialMatched) hasAnyMatch = true;
numbers.add(
_buildNumberWidget(
context,
ticket.regionTwoNumber,
isMatched: isSpecialMatched,
isSpecial: true,
allUnmatched: !hasAnyMatch && ticket.drawStatus >= 1,
),
);
return Wrap(
spacing: 6,
crossAxisAlignment: WrapCrossAlignment.center,
children: numbers,
);
}
Widget _buildNumberWidget(
BuildContext context,
int number, {
bool isMatched = false,
bool isSpecial = false,
bool allUnmatched = false,
}) {
Color backgroundColor;
Color textColor;
Color borderColor;
if (isMatched) {
backgroundColor = Colors.green;
textColor = Colors.white;
borderColor = Colors.green;
} else {
backgroundColor =
isSpecial
? Theme.of(context).colorScheme.secondary
: Theme.of(context).colorScheme.surface;
textColor =
isSpecial
? Theme.of(context).colorScheme.onSecondary
: Theme.of(context).colorScheme.onSurface;
borderColor =
isSpecial
? Theme.of(context).colorScheme.secondary
: Theme.of(context).colorScheme.outline.withOpacity(0.3);
// Blend with red if all numbers are unmatched
if (allUnmatched) {
backgroundColor = Color.alphaBlend(
Colors.red.withOpacity(0.3),
backgroundColor,
);
if (!isSpecial) {
textColor = Color.alphaBlend(Colors.red.withOpacity(0.5), textColor);
}
}
}
return Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: backgroundColor,
border: Border.all(color: borderColor),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
number.toString().padLeft(2, '0'),
style: TextStyle(
color: textColor,
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
),
);
}
}
class LotteryRecordsList extends HookConsumerWidget {
const LotteryRecordsList({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final records = ref.watch(lotteryRecordsProvider());
return records.when(
data: (recordsList) {
if (recordsList.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Symbols.history,
size: 48,
color: Theme.of(context).colorScheme.outline,
),
const Gap(16),
Text(
'noDrawHistory'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
],
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: recordsList.length,
itemBuilder: (context, index) {
final record = recordsList[index];
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Symbols.celebration,
color: Theme.of(context).colorScheme.primary,
),
const Gap(8),
Text(
DateFormat.yMd().format(record.drawDate),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
const Gap(8),
Text(
'${'winningNumbers'.tr()}: ${record.winningRegionOneNumbers.join(', ')}',
style: Theme.of(context).textTheme.bodyMedium,
),
const Gap(4),
Text(
'${'specialNumber'.tr()}: ${record.winningRegionTwoNumber}',
style: Theme.of(context).textTheme.bodyMedium,
),
const Gap(8),
Text(
'${'totalTickets'.tr()}: ${record.totalTickets}',
style: Theme.of(context).textTheme.bodySmall,
),
const Gap(4),
Text(
'${'totalWinners'.tr()}: ${record.totalPrizesAwarded}',
style: Theme.of(context).textTheme.bodySmall,
),
const Gap(4),
Text(
'${'prizePool'.tr()}: ${record.totalPrizeAmount.toStringAsFixed(2)} ${'walletCurrencyShortPoints'.tr()}',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
);
},
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')),
);
}
}
class LotteryPurchaseSheet extends StatefulWidget {
const LotteryPurchaseSheet({super.key});
@override
State<LotteryPurchaseSheet> createState() => _LotteryPurchaseSheetState();
}
class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
final List<int> selectedNumbers = [];
int multiplier = 1;
@override
Widget build(BuildContext context) {
final totalCost = 10.0 * multiplier; // Base cost of 10 ISP per ticket
return SheetScaffold(
titleText: 'buyLotteryTicket'.tr(),
child: Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Number Selection Section
Text(
'selectNumbers'.tr(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.primary,
),
),
const Gap(8),
Text(
'select5UniqueNumbers'.tr(),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
const Gap(4),
Text(
'The last selected number will be your special number.',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.w500,
),
),
const Gap(16),
// Number Grid
_buildNumberGrid(),
const Gap(16),
// Multiplier Section
Text(
'selectMultiplier'.tr(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.primary,
),
),
const Gap(16),
_buildMultiplierSelector(),
const Gap(16),
// Cost Summary
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('baseCost'.tr()),
Text('10.00 ${'walletCurrencyShortPoints'.tr()}'),
],
),
if (multiplier > 1) ...[
const Gap(8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'multiplier'.tr(
args: [multiplier.toString()],
),
),
Text(
'+ ${(10.0 * (multiplier - 1)).toStringAsFixed(2)} ${'walletCurrencyShortPoints'.tr()}',
),
],
),
],
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'totalCost'.tr(),
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(
'${totalCost.toStringAsFixed(2)} ${'walletCurrencyShortPoints'.tr()}',
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
],
),
],
),
),
),
const Gap(16),
// Prize Structure
Text(
'prizeStructure'.tr(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.primary,
),
),
const Gap(8),
_buildPrizeStructure(),
],
),
),
),
// Action Buttons
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('cancel'.tr()),
),
),
const Gap(8),
Expanded(
child: FilledButton(
onPressed: _canPurchase ? _purchaseTicket : null,
child: Text('purchase'.tr()),
),
),
],
),
),
],
),
);
}
Widget _buildNumberGrid() {
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 10,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemCount: 100,
itemBuilder: (context, index) {
final number = index;
final isSelected = selectedNumbers.contains(number);
final isSpecialNumber =
selectedNumbers.isNotEmpty &&
selectedNumbers.last == number &&
selectedNumbers.length == 6;
return GestureDetector(
onTap: () => _toggleNumber(number),
child: Container(
decoration: BoxDecoration(
color:
isSpecialNumber
? Theme.of(context).colorScheme.secondary
: isSelected
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.surface,
border: Border.all(
color:
isSpecialNumber
? Theme.of(context).colorScheme.secondary
: isSelected
? Theme.of(context).colorScheme.primary
: Theme.of(
context,
).colorScheme.outline.withOpacity(0.3),
),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
number.toString().padLeft(2, '0'),
style: TextStyle(
color:
isSpecialNumber
? Theme.of(context).colorScheme.onSecondary
: isSelected
? Theme.of(context).colorScheme.onPrimary
: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
),
),
);
},
);
}
Widget _buildMultiplierSelector() {
return TextFormField(
initialValue: multiplier.toString(),
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'multiplierLabel'.tr(),
prefixText: 'x',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
),
onChanged: (value) {
final parsed = int.tryParse(value);
if (parsed != null && parsed >= 1) {
setState(() => multiplier = parsed);
}
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a multiplier';
}
final parsed = int.tryParse(value);
if (parsed == null || parsed < 1 || parsed > 10) {
return 'Multiplier must be between 1 and 10';
}
return null;
},
);
}
Widget _buildPrizeStructure() {
// Base rewards for matched numbers (0-5)
final baseRewards = [0, 10, 100, 500, 1000, 10000];
final prizeStructure = <String, String>{};
// Generate prize structure for 0-5 matches with and without special
for (int matches = 5; matches >= 0; matches--) {
final baseReward = baseRewards[matches];
// With special number match (x10 multiplier)
final specialReward = baseReward * 10;
prizeStructure['$matches+Special'] = specialReward.toStringAsFixed(2);
// Without special number match
if (matches > 0) {
prizeStructure[matches.toString()] = baseReward.toStringAsFixed(2);
}
}
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children:
prizeStructure.entries.map((entry) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
entry.key == '0+Special'
? 'specialOnly'.tr()
: entry.key.tr(),
),
Text(
'${entry.value} ${'walletCurrencyShortPoints'.tr()}',
),
],
),
);
}).toList(),
),
),
);
}
void _toggleNumber(int number) {
setState(() {
if (selectedNumbers.contains(number)) {
selectedNumbers.remove(number);
} else if (selectedNumbers.length < 6) {
selectedNumbers.add(number);
}
});
}
bool get _canPurchase {
return selectedNumbers.length == 6;
}
Future<void> _purchaseTicket() async {
if (!_canPurchase) return;
// Sort all numbers except the last one (special number)
final regularNumbers = selectedNumbers.sublist(0, 5)..sort();
final specialNumber = selectedNumbers.last;
final purchaseData = {
'region_one_numbers': regularNumbers,
'region_two_number': specialNumber,
'multiplier': multiplier,
};
if (mounted) Navigator.of(context).pop(purchaseData);
}
}

307
lib/screens/lottery.g.dart Normal file
View File

@@ -0,0 +1,307 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'lottery.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$lotteryTicketsHash() => r'dd17cd721fc3b176ffa0ee0a85d0d850740e5e80';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [lotteryTickets].
@ProviderFor(lotteryTickets)
const lotteryTicketsProvider = LotteryTicketsFamily();
/// See also [lotteryTickets].
class LotteryTicketsFamily extends Family<AsyncValue<List<SnLotteryTicket>>> {
/// See also [lotteryTickets].
const LotteryTicketsFamily();
/// See also [lotteryTickets].
LotteryTicketsProvider call({int offset = 0, int take = 20}) {
return LotteryTicketsProvider(offset: offset, take: take);
}
@override
LotteryTicketsProvider getProviderOverride(
covariant LotteryTicketsProvider provider,
) {
return call(offset: provider.offset, take: provider.take);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'lotteryTicketsProvider';
}
/// See also [lotteryTickets].
class LotteryTicketsProvider
extends AutoDisposeFutureProvider<List<SnLotteryTicket>> {
/// See also [lotteryTickets].
LotteryTicketsProvider({int offset = 0, int take = 20})
: this._internal(
(ref) => lotteryTickets(
ref as LotteryTicketsRef,
offset: offset,
take: take,
),
from: lotteryTicketsProvider,
name: r'lotteryTicketsProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$lotteryTicketsHash,
dependencies: LotteryTicketsFamily._dependencies,
allTransitiveDependencies:
LotteryTicketsFamily._allTransitiveDependencies,
offset: offset,
take: take,
);
LotteryTicketsProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.offset,
required this.take,
}) : super.internal();
final int offset;
final int take;
@override
Override overrideWith(
FutureOr<List<SnLotteryTicket>> Function(LotteryTicketsRef provider) create,
) {
return ProviderOverride(
origin: this,
override: LotteryTicketsProvider._internal(
(ref) => create(ref as LotteryTicketsRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
offset: offset,
take: take,
),
);
}
@override
AutoDisposeFutureProviderElement<List<SnLotteryTicket>> createElement() {
return _LotteryTicketsProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is LotteryTicketsProvider &&
other.offset == offset &&
other.take == take;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, offset.hashCode);
hash = _SystemHash.combine(hash, take.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin LotteryTicketsRef on AutoDisposeFutureProviderRef<List<SnLotteryTicket>> {
/// The parameter `offset` of this provider.
int get offset;
/// The parameter `take` of this provider.
int get take;
}
class _LotteryTicketsProviderElement
extends AutoDisposeFutureProviderElement<List<SnLotteryTicket>>
with LotteryTicketsRef {
_LotteryTicketsProviderElement(super.provider);
@override
int get offset => (origin as LotteryTicketsProvider).offset;
@override
int get take => (origin as LotteryTicketsProvider).take;
}
String _$lotteryRecordsHash() => r'55c657460f18d9777741d09013b445ca036863f3';
/// See also [lotteryRecords].
@ProviderFor(lotteryRecords)
const lotteryRecordsProvider = LotteryRecordsFamily();
/// See also [lotteryRecords].
class LotteryRecordsFamily extends Family<AsyncValue<List<SnLotteryRecord>>> {
/// See also [lotteryRecords].
const LotteryRecordsFamily();
/// See also [lotteryRecords].
LotteryRecordsProvider call({int offset = 0, int take = 20}) {
return LotteryRecordsProvider(offset: offset, take: take);
}
@override
LotteryRecordsProvider getProviderOverride(
covariant LotteryRecordsProvider provider,
) {
return call(offset: provider.offset, take: provider.take);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'lotteryRecordsProvider';
}
/// See also [lotteryRecords].
class LotteryRecordsProvider
extends AutoDisposeFutureProvider<List<SnLotteryRecord>> {
/// See also [lotteryRecords].
LotteryRecordsProvider({int offset = 0, int take = 20})
: this._internal(
(ref) => lotteryRecords(
ref as LotteryRecordsRef,
offset: offset,
take: take,
),
from: lotteryRecordsProvider,
name: r'lotteryRecordsProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$lotteryRecordsHash,
dependencies: LotteryRecordsFamily._dependencies,
allTransitiveDependencies:
LotteryRecordsFamily._allTransitiveDependencies,
offset: offset,
take: take,
);
LotteryRecordsProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.offset,
required this.take,
}) : super.internal();
final int offset;
final int take;
@override
Override overrideWith(
FutureOr<List<SnLotteryRecord>> Function(LotteryRecordsRef provider) create,
) {
return ProviderOverride(
origin: this,
override: LotteryRecordsProvider._internal(
(ref) => create(ref as LotteryRecordsRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
offset: offset,
take: take,
),
);
}
@override
AutoDisposeFutureProviderElement<List<SnLotteryRecord>> createElement() {
return _LotteryRecordsProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is LotteryRecordsProvider &&
other.offset == offset &&
other.take == take;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, offset.hashCode);
hash = _SystemHash.combine(hash, take.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin LotteryRecordsRef on AutoDisposeFutureProviderRef<List<SnLotteryRecord>> {
/// The parameter `offset` of this provider.
int get offset;
/// The parameter `take` of this provider.
int get take;
}
class _LotteryRecordsProviderElement
extends AutoDisposeFutureProviderElement<List<SnLotteryRecord>>
with LotteryRecordsRef {
_LotteryRecordsProviderElement(super.provider);
@override
int get offset => (origin as LotteryRecordsProvider).offset;
@override
int get take => (origin as LotteryRecordsProvider).take;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View File

@@ -237,7 +237,7 @@ class PostCategoryDetailScreen extends HookConsumerWidget {
loading: () => ResponseLoadingWidget(),
),
),
),
).padding(horizontal: 8),
),
),
const SliverGap(4),

View File

@@ -22,6 +22,7 @@ import 'package:island/widgets/response.dart';
import 'package:island/utils/share_utils.dart';
import 'package:island/widgets/safety/abuse_report_helper.dart';
import 'package:island/widgets/share/share_sheet.dart';
import 'package:island/screens/thought/think_sheet.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart';
@@ -289,7 +290,7 @@ class PostActionButtons extends HookConsumerWidget {
builder: (context) => PostAwardHistorySheet(postId: post.id),
);
},
icon: const Icon(Symbols.star),
icon: const Icon(Symbols.emoji_events),
label:
post.awardedScore > 0
? Text('${formatScore(post.awardedScore)} pts')
@@ -297,6 +298,16 @@ class PostActionButtons extends HookConsumerWidget {
),
);
actions.add(
FilledButton.tonalIcon(
onPressed: () {
ThoughtSheet.show(context, attachedPosts: [post.id]);
},
icon: const Icon(Symbols.smart_toy),
label: Text('aiThought'.tr()),
),
);
actions.add(
Row(
mainAxisSize: MainAxisSize.min,

View File

@@ -285,7 +285,9 @@ Future<List<SnAccountBadge>> publisherBadges(Ref ref, String pubName) async {
final pub = await ref.watch(publisherProvider(pubName).future);
if (pub.type != 0 || pub.account == null) return [];
final apiClient = ref.watch(apiClientProvider);
final resp = await apiClient.get("/id/accounts/${pub.account!.name}/badges");
final resp = await apiClient.get(
"/pass/accounts/${pub.account!.name}/badges",
);
return List<SnAccountBadge>.from(
resp.data.map((x) => SnAccountBadge.fromJson(x)),
);

View File

@@ -145,7 +145,7 @@ class _PublisherProviderElement
String get uname => (origin as PublisherProvider).uname;
}
String _$publisherBadgesHash() => r'527efad74225fbacf558ac5db160ecce53a60c62';
String _$publisherBadgesHash() => r'26776fd6cb611953f52bdb6a7dfa004c34d5cd8e';
/// See also [publisherBadges].
@ProviderFor(publisherBadges)

View File

@@ -47,9 +47,7 @@ Future<Color?> realmAppbarForegroundColor(Ref ref, String realmSlug) async {
Future<SnRealmMember?> realmIdentity(Ref ref, String realmSlug) async {
try {
final apiClient = ref.watch(apiClientProvider);
final response = await apiClient.get(
'/sphere/realms/$realmSlug/members/me',
);
final response = await apiClient.get('/pass/realms/$realmSlug/members/me');
return SnRealmMember.fromJson(response.data);
} catch (err) {
if (err is DioException && err.response?.statusCode == 404) {
@@ -117,7 +115,7 @@ class RealmDetailScreen extends HookConsumerWidget {
onPressed: () async {
try {
final apiClient = ref.read(apiClientProvider);
await apiClient.post('/sphere/realms/$slug/members/me');
await apiClient.post('/pass/realms/$slug/members/me');
ref.invalidate(realmIdentityProvider(slug));
ref.invalidate(realmsJoinedProvider);
showSnackBar('realmJoinSuccess'.tr());
@@ -432,7 +430,7 @@ class _RealmActionMenu extends HookConsumerWidget {
).then((confirm) {
if (confirm) {
final client = ref.watch(apiClientProvider);
client.delete('/sphere/realms/$realmSlug');
client.delete('/pass/realms/$realmSlug');
ref.invalidate(realmsJoinedProvider);
if (context.mounted) {
context.pop(true);
@@ -465,7 +463,7 @@ class _RealmActionMenu extends HookConsumerWidget {
if (confirm) {
final client = ref.watch(apiClientProvider);
await client.delete(
'/sphere/realms/$realmSlug/members/me',
'/pass/realms/$realmSlug/members/me',
);
ref.invalidate(realmsJoinedProvider);
if (context.mounted) {
@@ -505,7 +503,7 @@ class _RealmActionMenu extends HookConsumerWidget {
if (confirm) {
final client = ref.watch(apiClientProvider);
await client.delete(
'/sphere/realms/$realmSlug/members/me',
'/pass/realms/$realmSlug/members/me',
);
ref.invalidate(realmsJoinedProvider);
if (context.mounted) {
@@ -539,7 +537,7 @@ class RealmMemberListNotifier extends _$RealmMemberListNotifier
final offset = cursor != null ? int.parse(cursor) : 0;
final response = await apiClient.get(
'/sphere/realms/$realmSlug/members',
'/pass/realms/$realmSlug/members',
queryParameters: {
'offset': offset,
'take': _pageSize,
@@ -592,7 +590,7 @@ class _RealmMemberListSheet extends HookConsumerWidget {
try {
final apiClient = ref.watch(apiClientProvider);
await apiClient.post(
'/sphere/realms/invites/$realmSlug',
'/pass/realms/invites/$realmSlug',
data: {'related_user_id': result.id, 'role': 0},
);
// Refresh the provider
@@ -729,7 +727,7 @@ class _RealmMemberListSheet extends HookConsumerWidget {
try {
final apiClient = ref.watch(apiClientProvider);
await apiClient.delete(
'/sphere/realms/$realmSlug/members/${member.accountId}',
'/pass/realms/$realmSlug/members/${member.accountId}',
);
// Refresh the provider
ref.invalidate(memberListProvider);
@@ -860,7 +858,7 @@ class _RealmMemberRoleSheet extends HookConsumerWidget {
final apiClient = ref.read(apiClientProvider);
await apiClient.patch(
'/sphere/realms/$realmSlug/members/${member.accountId}/role',
'/pass/realms/$realmSlug/members/${member.accountId}/role',
data: newRole,
);

View File

@@ -155,7 +155,7 @@ class _RealmAppbarForegroundColorProviderElement
(origin as RealmAppbarForegroundColorProvider).realmSlug;
}
String _$realmIdentityHash() => r'c5e2977d243260947b919bc27146c134e34f0db1';
String _$realmIdentityHash() => r'd5a3ecc6eeec291cebbfc9a45d8aac7195366381';
/// See also [realmIdentity].
@ProviderFor(realmIdentity)
@@ -399,7 +399,7 @@ class _RealmChatRoomsProviderElement
}
String _$realmMemberListNotifierHash() =>
r'db1fd8a6741dfb3d5bb921d5d965f0cfdc0e7bcc';
r'ab38c550c43cbf93d4c3e92e6658d76f40252c1f';
abstract class _$RealmMemberListNotifier
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnRealmMember>> {

View File

@@ -122,7 +122,7 @@ class EditRealmScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
final resp = await client.request(
'/sphere${slug == null ? '/realms' : '/realms/$slug'}',
'/pass${slug == null ? '/realms' : '/realms/$slug'}',
data: {
'slug': slugController.text,
'name': nameController.text,

View File

@@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -9,6 +10,7 @@ import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/content/sheet.dart';
import 'package:island/widgets/navigation/fab_menu.dart';
import 'package:island/widgets/response.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -21,7 +23,7 @@ part 'realms.g.dart';
@riverpod
Future<List<SnRealm>> realmsJoined(Ref ref) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/realms');
final resp = await client.get('/pass/realms');
return resp.data.map((e) => SnRealm.fromJson(e)).cast<SnRealm>().toList();
}
@@ -29,7 +31,7 @@ Future<List<SnRealm>> realmsJoined(Ref ref) async {
Future<SnRealm?> realm(Ref ref, String? identifier) async {
if (identifier == null) return null;
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/realms/$identifier');
final resp = await client.get('/pass/realms/$identifier');
return SnRealm.fromJson(resp.data);
}
@@ -41,6 +43,20 @@ class RealmListScreen extends HookConsumerWidget {
final realms = ref.watch(realmsJoinedProvider);
final realmInvites = ref.watch(realmInvitesProvider);
useEffect(() {
// Set FAB type to realm
final fabMenuNotifier = ref.read(fabMenuTypeProvider.notifier);
WidgetsBinding.instance.addPostFrameCallback((_) {
fabMenuNotifier.state = FabMenuType.realm;
});
return () {
// Clean up: reset FAB type to main
WidgetsBinding.instance.addPostFrameCallback((_) {
fabMenuNotifier.state = FabMenuType.main;
});
};
}, []);
return AppScaffold(
isNoBackground: false,
appBar: AppBar(
@@ -78,17 +94,6 @@ class RealmListScreen extends HookConsumerWidget {
const Gap(8),
],
),
floatingActionButton: FloatingActionButton(
heroTag: const Key("realms-page-fab"),
child: const Icon(Symbols.add),
onPressed: () {
context.pushNamed('realmNew').then((value) {
if (value != null) {
ref.invalidate(realmsJoinedProvider);
}
});
},
),
body: ExtendedRefreshIndicator(
child: realms.when(
data:
@@ -128,7 +133,7 @@ class RealmListScreen extends HookConsumerWidget {
@riverpod
Future<List<SnRealmMember>> realmInvites(Ref ref) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/realms/invites');
final resp = await client.get('/pass/realms/invites');
return resp.data
.map((e) => SnRealmMember.fromJson(e))
.cast<SnRealmMember>()
@@ -145,9 +150,7 @@ class _RealmInviteSheet extends HookConsumerWidget {
Future<void> acceptInvite(SnRealmMember invite) async {
try {
final client = ref.read(apiClientProvider);
await client.post(
'/sphere/realms/invites/${invite.realm!.slug}/accept',
);
await client.post('/pass/realms/invites/${invite.realm!.slug}/accept');
ref.invalidate(realmInvitesProvider);
ref.invalidate(realmsJoinedProvider);
} catch (err) {
@@ -158,9 +161,7 @@ class _RealmInviteSheet extends HookConsumerWidget {
Future<void> declineInvite(SnRealmMember invite) async {
try {
final client = ref.read(apiClientProvider);
await client.post(
'/sphere/realms/invites/${invite.realm!.slug}/decline',
);
await client.post('/pass/realms/invites/${invite.realm!.slug}/decline');
ref.invalidate(realmInvitesProvider);
} catch (err) {
showErrorAlert(err);

View File

@@ -6,7 +6,7 @@ part of 'realms.dart';
// RiverpodGenerator
// **************************************************************************
String _$realmsJoinedHash() => r'e8083f02ffae450bba2470c31757675b4df32cd0';
String _$realmsJoinedHash() => r'b15029acd38f03bbbb8708adb78f25ac357a0421';
/// See also [realmsJoined].
@ProviderFor(realmsJoined)
@@ -22,7 +22,7 @@ final realmsJoinedProvider = AutoDisposeFutureProvider<List<SnRealm>>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef RealmsJoinedRef = AutoDisposeFutureProviderRef<List<SnRealm>>;
String _$realmHash() => r'4650b17608a9ee14170ef20295eb14d295e909c9';
String _$realmHash() => r'71a126ab2810566646e1629290c1ce9ffa0839e3';
/// Copied from Dart SDK
class _SystemHash {
@@ -156,7 +156,7 @@ class _RealmProviderElement extends AutoDisposeFutureProviderElement<SnRealm?>
String? get identifier => (origin as RealmProvider).identifier;
}
String _$realmInvitesHash() => r'ed73443c6423b92ed72982be2a93b7dcc7ce3945';
String _$realmInvitesHash() => r'92cce0978c7ca8813e27ae42fc6f3a93a09a8962';
/// See also [realmInvites].
@ProviderFor(realmInvites)

View File

@@ -422,6 +422,48 @@ class SettingsScreen extends HookConsumerWidget {
),
),
// FAB position settings
ListTile(
minLeadingWidth: 48,
title: Text('fabPosition').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17),
leading: const Icon(Symbols.adjust),
trailing: DropdownButtonHideUnderline(
child: DropdownButton2<String>(
isExpanded: true,
items: [
DropdownMenuItem<String>(
value: 'left',
child: Text('Left').fontSize(14),
),
DropdownMenuItem<String>(
value: 'center',
child: Text('Center').fontSize(14),
),
DropdownMenuItem<String>(
value: 'right',
child: Text('Right').fontSize(14),
),
],
value: settings.fabPosition,
onChanged: (String? value) {
if (value != null) {
ref
.read(appSettingsNotifierProvider.notifier)
.setFabPosition(value);
showSnackBar('settingsApplied'.tr());
}
},
buttonStyleData: const ButtonStyleData(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 5),
height: 40,
width: 120,
),
menuItemStyleData: const MenuItemStyleData(height: 40),
),
),
),
// Card background opacity settings
ListTile(
minLeadingWidth: 48,

View File

@@ -168,7 +168,7 @@ class MarketplaceStickerPackDetailScreen extends HookConsumerWidget {
child: AspectRatio(
aspectRatio: 1,
child: CloudImageWidget(
fileId: sticker.imageId,
fileId: sticker.image.id,
fit: BoxFit.contain,
),
),

View File

@@ -8,7 +8,10 @@ import 'package:go_router/go_router.dart';
import 'package:island/screens/notification.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/navigation/conditional_bottom_nav.dart';
import 'package:island/widgets/navigation/fab_menu.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:island/pods/config.dart';
final currentRouteProvider = StateProvider<String?>((ref) => null);
@@ -50,10 +53,13 @@ class TabsScreen extends HookConsumerWidget {
label: 'explore'.tr(),
icon: const Icon(Symbols.explore),
),
NavigationDestination(label: 'chat'.tr(), icon: const Icon(Symbols.chat)),
NavigationDestination(
label: 'chat'.tr(),
icon: const Icon(Symbols.chat_rounded),
),
NavigationDestination(
label: 'realms'.tr(),
icon: const Icon(Symbols.workspaces),
icon: const Icon(Symbols.group),
),
NavigationDestination(
label: 'account'.tr(),
@@ -91,6 +97,13 @@ class TabsScreen extends HookConsumerWidget {
final currentIndex = getCurrentIndex();
final routes = kTabRoutes.sublist(
0,
isWideScreen(context) ? null : kWideScreenRouteStart,
);
final shouldShowFab = routes.contains(currentLocation) && !wideScreen;
final settings = ref.watch(appSettingsNotifierProvider);
if (isWideScreen(context)) {
return Container(
color: Theme.of(context).colorScheme.surfaceContainer,
@@ -109,6 +122,10 @@ class TabsScreen extends HookConsumerWidget {
.toList(),
selectedIndex: currentIndex,
onDestinationSelected: onDestinationSelected,
trailingAtBottom: true,
trailing: const FabMenu(
elevation: 0,
).padding(bottom: MediaQuery.of(context).padding.bottom + 16),
),
Expanded(
child: ClipRRect(
@@ -134,29 +151,62 @@ class TabsScreen extends HookConsumerWidget {
),
child: child ?? const SizedBox.shrink(),
),
floatingActionButton: shouldShowFab ? const FabMenu() : null,
floatingActionButtonLocation:
shouldShowFab
? _DockedFabLocation(context, settings.fabPosition)
: null,
bottomNavigationBar: ConditionalBottomNav(
child: ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 1, sigmaY: 1),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface.withOpacity(0.8),
),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: NavigationBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
overlayColor: const WidgetStatePropertyAll(
Colors.transparent,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: BottomAppBar(
height: 56,
padding: EdgeInsets.symmetric(horizontal: 24),
shape: AutomaticNotchedShape(
RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
surfaceTintColor: Colors.transparent,
height: 56,
labelBehavior: NavigationDestinationLabelBehavior.alwaysHide,
selectedIndex: currentIndex,
onDestinationSelected: onDestinationSelected,
destinations: destinations,
),
color: Theme.of(context).colorScheme.surface.withOpacity(0.8),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: () {
final navItems =
destinations.asMap().entries.map<Widget>((entry) {
int index = entry.key;
NavigationDestination dest = entry.value;
return IconButton(
icon: dest.icon,
onPressed: () => onDestinationSelected(index),
color:
index == currentIndex
? Theme.of(context).colorScheme.primary
: null,
);
}).toList();
// Add mock item to leave space for FAB based on position
final gapIndex = switch (settings.fabPosition) {
'left' => 0,
'right' => navItems.length,
_ => navItems.length ~/ 2, // center
};
navItems.insert(
gapIndex,
SizedBox(
width: settings.fabPosition == 'center' ? 72 : 48,
),
);
return navItems;
}(),
),
),
),
@@ -167,24 +217,32 @@ class TabsScreen extends HookConsumerWidget {
}
}
class TabbedFabLocation extends FloatingActionButtonLocation {
class _DockedFabLocation extends FloatingActionButtonLocation {
final BuildContext context;
final String fabPosition;
const TabbedFabLocation(this.context);
const _DockedFabLocation(this.context, this.fabPosition);
@override
Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {
final mediaQuery = MediaQuery.of(context);
final safeAreaPadding = mediaQuery.padding;
// Calculate position with proper safe area considerations
final double fabX =
// Position horizontally based on setting
final double fabX = switch (fabPosition) {
'left' => scaffoldGeometry.minInsets.left + 24,
'right' =>
scaffoldGeometry.scaffoldSize.width -
scaffoldGeometry.floatingActionButtonSize.width -
16 -
safeAreaPadding.right;
scaffoldGeometry.floatingActionButtonSize.width -
scaffoldGeometry.minInsets.right -
24,
_ =>
(scaffoldGeometry.scaffoldSize.width -
scaffoldGeometry.floatingActionButtonSize.width) /
2, // center
};
// Use safe area bottom padding + navigation bar height (typically 80px)
// Position closer to bottom with reduced padding
final double fabY =
scaffoldGeometry.scaffoldSize.height -
scaffoldGeometry.floatingActionButtonSize.height -

View File

@@ -0,0 +1,323 @@
import "dart:convert";
import "package:dio/dio.dart";
import "package:easy_localization/easy_localization.dart";
import "package:flutter/material.dart";
import "package:flutter_hooks/flutter_hooks.dart";
import "package:gap/gap.dart";
import "package:riverpod_annotation/riverpod_annotation.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:island/models/thought.dart";
import "package:island/pods/network.dart";
import "package:island/pods/userinfo.dart";
import "package:island/widgets/alert.dart";
import "package:island/widgets/app_scaffold.dart";
import "package:island/widgets/response.dart";
import "package:island/widgets/thought/thought_sequence_list.dart";
import "package:island/widgets/thought/thought_shared.dart";
import "package:material_symbols_icons/material_symbols_icons.dart";
import "package:super_sliver_list/super_sliver_list.dart";
import "package:collection/collection.dart";
part 'think.g.dart';
@riverpod
Future<List<SnThinkingThought>> thoughtSequence(
Ref ref,
String sequenceId,
) async {
final apiClient = ref.watch(apiClientProvider);
final response = await apiClient.get(
'/insight/thought/sequences/$sequenceId',
);
return (response.data as List)
.map((e) => SnThinkingThought.fromJson(e))
.toList();
}
class ThoughtScreen extends HookConsumerWidget {
const ThoughtScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final selectedSequenceId = useState<String?>(null);
final thoughts =
selectedSequenceId.value != null
? ref.watch(thoughtSequenceProvider(selectedSequenceId.value!))
: const AsyncValue<List<SnThinkingThought>>.data([]);
final localThoughts = useState<List<SnThinkingThought>>([]);
final currentTopic = useState<String?>('aiThought'.tr());
final messageController = useTextEditingController();
final scrollController = useScrollController();
final isStreaming = useState(false);
final streamingText = useState<String>('');
final functionCalls = useState<List<String>>([]);
final reasoningChunks = useState<List<String>>([]);
final listController = useMemoized(() => ListController(), []);
// Update local thoughts when provider data changes
useEffect(() {
thoughts.whenData((data) {
// Server returns messages in DESC order (newest first), keep as-is for UI
localThoughts.value = data;
// Update topic from the first thought's sequence
if (data.isNotEmpty && data.first.sequence?.topic != null) {
currentTopic.value = data.first.sequence!.topic;
} else {
currentTopic.value = 'aiThought'.tr();
}
});
return null;
}, [thoughts]);
// Scroll to bottom when thoughts change or streaming state changes
useEffect(() {
if (localThoughts.value.isNotEmpty || isStreaming.value) {
WidgetsBinding.instance.addPostFrameCallback((_) {
scrollController.animateTo(
0,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
});
}
return null;
}, [localThoughts.value.length, isStreaming.value]);
void sendMessage() async {
if (messageController.text.trim().isEmpty) return;
final userMessage = messageController.text.trim();
// Add user message to local thoughts
final userInfo = ref.read(userInfoProvider);
final now = DateTime.now();
final userThought = SnThinkingThought(
id: 'user-${DateTime.now().millisecondsSinceEpoch}',
content: userMessage,
files: [],
role: ThinkingThoughtRole.user,
sequenceId: selectedSequenceId.value ?? '',
createdAt: now,
updatedAt: now,
sequence:
selectedSequenceId.value != null
? thoughts.value?.firstOrNull?.sequence ??
SnThinkingSequence(
id: selectedSequenceId.value!,
accountId: '',
createdAt: now,
updatedAt: now,
)
: SnThinkingSequence(
id: '',
accountId: userInfo.value!.id,
createdAt: now,
updatedAt: now,
),
);
localThoughts.value = [userThought, ...localThoughts.value];
final request = StreamThinkingRequest(
userMessage: userMessage,
sequenceId: selectedSequenceId.value,
accpetProposals: ['post_create'],
attachedMessages: [], // Message datas
attachedPosts: [], // ID list for posts
);
try {
isStreaming.value = true;
streamingText.value = '';
functionCalls.value = [];
reasoningChunks.value = [];
final apiClient = ref.read(apiClientProvider);
final response = await apiClient.post(
'/insight/thought',
data: request.toJson(),
options: Options(
responseType: ResponseType.stream,
sendTimeout: Duration(minutes: 1),
receiveTimeout: Duration(minutes: 1),
),
);
final stream = response.data.stream;
final lineBuffer = StringBuffer();
stream.listen(
(data) {
final chunk = utf8.decode(data);
lineBuffer.write(chunk);
final lines = lineBuffer.toString().split('\n');
lineBuffer.clear();
lineBuffer.write(lines.last); // keep incomplete line
for (final line in lines.sublist(0, lines.length - 1)) {
if (line.trim().isEmpty) continue;
try {
if (line.startsWith('data: ')) {
final jsonStr = line.substring(6);
final event = jsonDecode(jsonStr);
final type = event['type'];
final eventData = event['data'];
if (type == 'text') {
streamingText.value += eventData;
} else if (type == 'function_call') {
functionCalls.value = [
...functionCalls.value,
JsonEncoder.withIndent(' ').convert(eventData),
];
} else if (type == 'reasoning') {
reasoningChunks.value = [
...reasoningChunks.value,
eventData,
];
}
} else if (line.startsWith('topic: ')) {
final jsonStr = line.substring(7);
final event = jsonDecode(jsonStr);
currentTopic.value = event['data'];
} else if (line.startsWith('thought: ')) {
final jsonStr = line.substring(9);
final event = jsonDecode(jsonStr);
final aiThought = SnThinkingThought.fromJson(event['data']);
localThoughts.value = [aiThought, ...localThoughts.value];
if (selectedSequenceId.value == null &&
aiThought.sequenceId.isNotEmpty) {
selectedSequenceId.value = aiThought.sequenceId;
}
isStreaming.value = false;
}
} catch (e) {
// Ignore parsing errors for individual events
}
}
},
onDone: () {
if (isStreaming.value) {
isStreaming.value = false;
showErrorAlert('thoughtParseError'.tr());
}
},
onError: (error) {
isStreaming.value = false;
if (error is DioException && error.response?.data is ResponseBody) {
showErrorAlert('toughtParseError'.tr());
} else {
showErrorAlert(error);
}
},
);
messageController.clear();
FocusManager.instance.primaryFocus?.unfocus();
} catch (error) {
isStreaming.value = false;
showErrorAlert(error);
}
}
return AppScaffold(
isNoBackground: false,
appBar: AppBar(
title: Text(currentTopic.value ?? 'aiThought'.tr()),
actions: [
IconButton(
icon: const Icon(Symbols.history),
onPressed: () {
// Show sequence selector
showModalBottomSheet(
context: context,
builder:
(context) => ThoughtSequenceSelector(
onSequenceSelected: (sequenceId) {
selectedSequenceId.value = sequenceId;
},
),
);
},
),
if (localThoughts.value.isNotEmpty &&
!isStreaming.value &&
localThoughts.value.last.role == ThinkingThoughtRole.assistant)
IconButton(
icon: const Icon(Symbols.add),
tooltip: 'thoughtNewConversation'.tr(),
onPressed: () {
// Clear current conversation and start new one
selectedSequenceId.value = null;
localThoughts.value = [];
currentTopic.value = 'aiThought'.tr();
messageController.clear();
},
),
const Gap(8),
],
),
body: Center(
child: Container(
constraints: BoxConstraints(maxWidth: 640),
child: Column(
children: [
Expanded(
child: thoughts.when(
data:
(thoughtList) => SuperListView.builder(
listController: listController,
controller: scrollController,
padding: const EdgeInsets.only(top: 16, bottom: 16),
reverse: true,
itemCount:
localThoughts.value.length +
(isStreaming.value ? 1 : 0),
itemBuilder: (context, index) {
if (isStreaming.value && index == 0) {
return ThoughtItem(
isStreaming: true,
streamingText: streamingText.value,
reasoningChunks: reasoningChunks.value,
streamingFunctionCalls: functionCalls.value,
);
}
final thoughtIndex =
isStreaming.value ? index - 1 : index;
final thought = localThoughts.value[thoughtIndex];
return ThoughtItem(
thought: thought,
thoughtIndex: thoughtIndex,
);
},
),
loading:
() => const Center(child: CircularProgressIndicator()),
error:
(error, _) => ResponseErrorWidget(
error: error,
onRetry:
() =>
selectedSequenceId.value != null
? ref.invalidate(
thoughtSequenceProvider(
selectedSequenceId.value!,
),
)
: null,
),
),
),
ThoughtInput(
messageController: messageController,
isStreaming: isStreaming.value,
onSend: sendMessage,
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,156 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'think.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$thoughtSequenceHash() => r'2a93c0a04f9a720ba474c02a36502940fb7f3ed7';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [thoughtSequence].
@ProviderFor(thoughtSequence)
const thoughtSequenceProvider = ThoughtSequenceFamily();
/// See also [thoughtSequence].
class ThoughtSequenceFamily
extends Family<AsyncValue<List<SnThinkingThought>>> {
/// See also [thoughtSequence].
const ThoughtSequenceFamily();
/// See also [thoughtSequence].
ThoughtSequenceProvider call(String sequenceId) {
return ThoughtSequenceProvider(sequenceId);
}
@override
ThoughtSequenceProvider getProviderOverride(
covariant ThoughtSequenceProvider provider,
) {
return call(provider.sequenceId);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'thoughtSequenceProvider';
}
/// See also [thoughtSequence].
class ThoughtSequenceProvider
extends AutoDisposeFutureProvider<List<SnThinkingThought>> {
/// See also [thoughtSequence].
ThoughtSequenceProvider(String sequenceId)
: this._internal(
(ref) => thoughtSequence(ref as ThoughtSequenceRef, sequenceId),
from: thoughtSequenceProvider,
name: r'thoughtSequenceProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$thoughtSequenceHash,
dependencies: ThoughtSequenceFamily._dependencies,
allTransitiveDependencies:
ThoughtSequenceFamily._allTransitiveDependencies,
sequenceId: sequenceId,
);
ThoughtSequenceProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.sequenceId,
}) : super.internal();
final String sequenceId;
@override
Override overrideWith(
FutureOr<List<SnThinkingThought>> Function(ThoughtSequenceRef provider)
create,
) {
return ProviderOverride(
origin: this,
override: ThoughtSequenceProvider._internal(
(ref) => create(ref as ThoughtSequenceRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
sequenceId: sequenceId,
),
);
}
@override
AutoDisposeFutureProviderElement<List<SnThinkingThought>> createElement() {
return _ThoughtSequenceProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is ThoughtSequenceProvider && other.sequenceId == sequenceId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, sequenceId.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin ThoughtSequenceRef
on AutoDisposeFutureProviderRef<List<SnThinkingThought>> {
/// The parameter `sequenceId` of this provider.
String get sequenceId;
}
class _ThoughtSequenceProviderElement
extends AutoDisposeFutureProviderElement<List<SnThinkingThought>>
with ThoughtSequenceRef {
_ThoughtSequenceProviderElement(super.provider);
@override
String get sequenceId => (origin as ThoughtSequenceProvider).sequenceId;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View File

@@ -0,0 +1,243 @@
import "dart:convert";
import "package:dio/dio.dart";
import "package:easy_localization/easy_localization.dart";
import "package:flutter/material.dart";
import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:island/models/thought.dart";
import "package:island/pods/network.dart";
import "package:island/pods/userinfo.dart";
import "package:island/widgets/alert.dart";
import "package:island/widgets/content/sheet.dart";
import "package:island/widgets/thought/thought_shared.dart";
import "package:super_sliver_list/super_sliver_list.dart";
class ThoughtSheet extends HookConsumerWidget {
final List<Map<String, dynamic>> attachedMessages;
final List<String> attachedPosts;
const ThoughtSheet({
super.key,
this.attachedMessages = const [],
this.attachedPosts = const [],
});
static Future<void> show(
BuildContext context, {
List<Map<String, dynamic>> attachedMessages = const [],
List<String> attachedPosts = const [],
}) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
useSafeArea: true,
builder:
(context) => ThoughtSheet(
attachedMessages: attachedMessages,
attachedPosts: attachedPosts,
),
);
}
@override
Widget build(BuildContext context, WidgetRef ref) {
final sequenceId = useState<String?>(null);
final localThoughts = useState<List<SnThinkingThought>>([]);
final currentTopic = useState<String?>('aiThought'.tr());
final messageController = useTextEditingController();
final scrollController = useScrollController();
final isStreaming = useState(false);
final streamingText = useState<String>('');
final functionCalls = useState<List<String>>([]);
final reasoningChunks = useState<List<String>>([]);
final listController = useMemoized(() => ListController(), []);
// Scroll to bottom when thoughts change or streaming state changes
useEffect(() {
if (localThoughts.value.isNotEmpty || isStreaming.value) {
WidgetsBinding.instance.addPostFrameCallback((_) {
scrollController.animateTo(
0,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
});
}
return null;
}, [localThoughts.value.length, isStreaming.value]);
void sendMessage() async {
if (messageController.text.trim().isEmpty) return;
final userMessage = messageController.text.trim();
// Add user message to local thoughts
final userInfo = ref.read(userInfoProvider);
final now = DateTime.now();
final userThought = SnThinkingThought(
id: 'user-${DateTime.now().millisecondsSinceEpoch}',
content: userMessage,
files: [],
role: ThinkingThoughtRole.user,
sequenceId: sequenceId.value ?? '',
createdAt: now,
updatedAt: now,
sequence: SnThinkingSequence(
id: sequenceId.value ?? '',
accountId: userInfo.value!.id,
createdAt: now,
updatedAt: now,
),
);
localThoughts.value = [userThought, ...localThoughts.value];
final request = StreamThinkingRequest(
userMessage: userMessage,
sequenceId: sequenceId.value,
accpetProposals: ['post_create'],
attachedMessages: attachedMessages,
attachedPosts: attachedPosts,
);
try {
isStreaming.value = true;
streamingText.value = '';
functionCalls.value = [];
reasoningChunks.value = [];
final apiClient = ref.read(apiClientProvider);
final response = await apiClient.post(
'/insight/thought',
data: request.toJson(),
options: Options(
responseType: ResponseType.stream,
sendTimeout: Duration(minutes: 1),
receiveTimeout: Duration(minutes: 1),
),
);
final stream = response.data.stream;
final lineBuffer = StringBuffer();
stream.listen(
(data) {
final chunk = utf8.decode(data);
lineBuffer.write(chunk);
final lines = lineBuffer.toString().split('\n');
lineBuffer.clear();
lineBuffer.write(lines.last); // keep incomplete line
for (final line in lines.sublist(0, lines.length - 1)) {
if (line.trim().isEmpty) continue;
try {
if (line.startsWith('data: ')) {
final jsonStr = line.substring(6);
final event = jsonDecode(jsonStr);
final type = event['type'];
final eventData = event['data'];
if (type == 'text') {
streamingText.value += eventData;
} else if (type == 'function_call') {
functionCalls.value = [
...functionCalls.value,
JsonEncoder.withIndent(' ').convert(eventData),
];
} else if (type == 'reasoning') {
reasoningChunks.value = [
...reasoningChunks.value,
eventData,
];
}
} else if (line.startsWith('topic: ')) {
final jsonStr = line.substring(7);
final event = jsonDecode(jsonStr);
currentTopic.value = event['data'];
} else if (line.startsWith('thought: ')) {
final jsonStr = line.substring(9);
final event = jsonDecode(jsonStr);
final aiThought = SnThinkingThought.fromJson(event['data']);
localThoughts.value = [aiThought, ...localThoughts.value];
if (sequenceId.value == null &&
aiThought.sequenceId.isNotEmpty) {
sequenceId.value = aiThought.sequenceId;
}
isStreaming.value = false;
}
} catch (e) {
// Ignore parsing errors for individual events
}
}
},
onDone: () {
if (isStreaming.value) {
isStreaming.value = false;
showErrorAlert('thoughtParseError'.tr());
}
},
onError: (error) {
isStreaming.value = false;
if (error is DioException && error.response?.data is ResponseBody) {
showErrorAlert('toughtParseError'.tr());
} else {
showErrorAlert(error);
}
},
);
messageController.clear();
FocusManager.instance.primaryFocus?.unfocus();
} catch (error) {
isStreaming.value = false;
showErrorAlert(error);
}
}
return SheetScaffold(
titleText: currentTopic.value ?? 'aiThought'.tr(),
child: Center(
child: Container(
constraints: BoxConstraints(maxWidth: 640),
child: Column(
children: [
Expanded(
child: SuperListView.builder(
listController: listController,
controller: scrollController,
padding: const EdgeInsets.only(top: 16, bottom: 16),
reverse: true,
itemCount:
localThoughts.value.length + (isStreaming.value ? 1 : 0),
itemBuilder: (context, index) {
if (isStreaming.value && index == 0) {
return ThoughtItem(
isStreaming: true,
streamingText: streamingText.value,
reasoningChunks: reasoningChunks.value,
streamingFunctionCalls: functionCalls.value,
);
}
final thoughtIndex = isStreaming.value ? index - 1 : index;
final thought = localThoughts.value[thoughtIndex];
return ThoughtItem(
thought: thought,
thoughtIndex: thoughtIndex,
);
},
),
),
ThoughtInput(
messageController: messageController,
isStreaming: isStreaming.value,
onSend: sendMessage,
attachedMessages: attachedMessages,
attachedPosts: attachedPosts,
),
],
),
),
),
);
}
}

View File

@@ -8,6 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/account.dart';
import 'package:island/models/wallet.dart';
import 'package:island/pods/network.dart';
import 'package:island/screens/lottery.dart';
import 'package:island/widgets/account/account_pfc.dart';
import 'package:island/widgets/account/account_picker.dart';
import 'package:island/widgets/app_scaffold.dart';
@@ -28,7 +29,7 @@ part 'wallet.g.dart';
Future<SnWallet?> walletCurrent(Ref ref) async {
try {
final apiClient = ref.watch(apiClientProvider);
final resp = await apiClient.get('/id/wallets');
final resp = await apiClient.get('/pass/wallets');
return SnWallet.fromJson(resp.data);
} catch (err) {
if (err is DioException && err.response?.statusCode == 404) {
@@ -41,7 +42,7 @@ Future<SnWallet?> walletCurrent(Ref ref) async {
@riverpod
Future<SnWalletStats> walletStats(Ref ref) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/id/wallets/stats');
final resp = await client.get('/pass/wallets/stats');
return SnWalletStats.fromJson(resp.data);
}
@@ -998,11 +999,6 @@ class _CreateTransferSheetState extends State<CreateTransferSheet> {
}
}
const Map<String, IconData> kCurrencyIconData = {
'points': Symbols.toll,
'golds': Symbols.attach_money,
};
@riverpod
class TransactionListNotifier extends _$TransactionListNotifier
with CursorPagingNotifierMixin<SnTransaction> {
@@ -1021,7 +1017,7 @@ class TransactionListNotifier extends _$TransactionListNotifier
final queryParams = {'offset': offset, 'take': _pageSize};
final response = await client.get(
'/id/wallets/transactions',
'/pass/wallets/transactions',
queryParameters: queryParams,
);
final total = int.parse(response.headers.value('X-Total') ?? '0');
@@ -1048,7 +1044,9 @@ Future<List<SnWalletFund>> walletFunds(
int take = 20,
}) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/id/wallets/funds?offset=$offset&take=$take');
final resp = await client.get(
'/pass/wallets/funds?offset=$offset&take=$take',
);
return (resp.data as List).map((e) => SnWalletFund.fromJson(e)).toList();
}
@@ -1060,7 +1058,7 @@ Future<List<SnWalletFundRecipient>> walletFundRecipients(
}) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get(
'/id/wallets/funds/recipients?offset=$offset&take=$take',
'/pass/wallets/funds/recipients?offset=$offset&take=$take',
);
return (resp.data as List)
.map((e) => SnWalletFundRecipient.fromJson(e))
@@ -1070,7 +1068,7 @@ Future<List<SnWalletFundRecipient>> walletFundRecipients(
@riverpod
Future<SnWalletFund> walletFund(Ref ref, String fundId) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/id/wallets/funds/$fundId');
final resp = await client.get('/pass/wallets/funds/$fundId');
return SnWalletFund.fromJson(resp.data);
}
@@ -1247,7 +1245,7 @@ class WalletScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final wallet = ref.watch(walletCurrentProvider);
final tabController = useTabController(initialLength: 2);
final tabController = useTabController(initialLength: 3);
final currentTabIndex = useState(0);
useEffect(() {
@@ -1262,7 +1260,7 @@ class WalletScreen extends HookConsumerWidget {
Future<void> createWallet() async {
final client = ref.read(apiClientProvider);
try {
await client.post('/id/wallets');
await client.post('/pass/wallets');
ref.invalidate(walletCurrentProvider);
} catch (err) {
showErrorAlert(err);
@@ -1326,18 +1324,20 @@ class WalletScreen extends HookConsumerWidget {
appBar: AppBar(
title: Text('wallet').tr(),
actions: [
IconButton(
icon: Icon(
currentTabIndex.value == 1
? Symbols.money_bag
: Symbols.swap_horiz,
),
onPressed: currentTabIndex.value == 1 ? createFund : createTransfer,
tooltip:
if (currentTabIndex.value != 2) // Hide for lottery tab
IconButton(
icon: Icon(
currentTabIndex.value == 1
? 'createFund'.tr()
: 'createTransfer'.tr(),
),
? Symbols.money_bag
: Symbols.swap_horiz,
),
onPressed:
currentTabIndex.value == 1 ? createFund : createTransfer,
tooltip:
currentTabIndex.value == 1
? 'createFund'.tr()
: 'createTransfer'.tr(),
),
const Gap(8),
],
),
@@ -1408,6 +1408,7 @@ class WalletScreen extends HookConsumerWidget {
tabs: [
Tab(text: 'transactions'.tr()),
Tab(text: 'myFunds'.tr()),
Tab(text: 'lottery'.tr()),
],
),
),
@@ -1485,6 +1486,9 @@ class WalletScreen extends HookConsumerWidget {
// My Funds Tab
_buildFundsList(context, ref),
// Lottery Tab
const LotteryTab(),
],
),
);
@@ -1762,14 +1766,16 @@ class WalletScreen extends HookConsumerWidget {
try {
showLoadingModal(context);
final resp = await client.post(
'/id/wallets/funds',
'/pass/wallets/funds',
data: fundData,
options: Options(headers: {'X-Noop': true}),
);
final fund = SnWalletFund.fromJson(resp.data);
if (fund.status == 0) return; // Already created
final orderResp = await client.post('/id/wallets/funds/${fund.id}/order');
final orderResp = await client.post(
'/pass/wallets/funds/${fund.id}/order',
);
final order = SnWalletOrder.fromJson(orderResp.data);
if (context.mounted) hideLoadingModal(context);
@@ -1808,7 +1814,7 @@ class WalletScreen extends HookConsumerWidget {
final client = ref.read(apiClientProvider);
try {
showLoadingModal(context);
await client.post('/id/wallets/transfer', data: transferData);
await client.post('/pass/wallets/transfer', data: transferData);
if (context.mounted) hideLoadingModal(context);
@@ -1855,3 +1861,8 @@ class WalletScreen extends HookConsumerWidget {
}
}
}
const Map<String, IconData> kCurrencyIconData = {
'points': Symbols.toll,
'golds': Symbols.attach_money,
};

View File

@@ -26,7 +26,7 @@ part 'wallet.g.dart';
Future<SnWallet?> walletCurrent(Ref ref) async {
try {
final apiClient = ref.watch(apiClientProvider);
final resp = await apiClient.get('/id/wallets');
final resp = await apiClient.get('/pass/wallets');
return SnWallet.fromJson(resp.data);
} catch (err) {
if (err is DioException && err.response?.statusCode == 404) {
@@ -491,7 +491,7 @@ class TransactionListNotifier extends _$TransactionListNotifier
final queryParams = {'offset': offset, 'take': _pageSize};
final response = await client.get(
'/id/wallets/transactions',
'/pass/wallets/transactions',
queryParameters: queryParams,
);
final total = int.parse(response.headers.value('X-Total') ?? '0');
@@ -518,7 +518,7 @@ Future<List<SnWalletFund>> walletFunds(
int take = 20,
}) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/id/wallets/funds?offset=$offset&take=$take');
final resp = await client.get('/pass/wallets/funds?offset=$offset&take=$take');
return (resp.data as List).map((e) => SnWalletFund.fromJson(e)).toList();
}
@@ -530,7 +530,7 @@ Future<List<SnWalletFundRecipient>> walletFundRecipients(
}) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get(
'/id/wallets/funds/recipients?offset=$offset&take=$take',
'/pass/wallets/funds/recipients?offset=$offset&take=$take',
);
return (resp.data as List)
.map((e) => SnWalletFundRecipient.fromJson(e))
@@ -540,14 +540,14 @@ Future<List<SnWalletFundRecipient>> walletFundRecipients(
@riverpod
Future<SnWalletFund> walletFund(Ref ref, String fundId) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/id/wallets/funds/$fundId');
final resp = await client.get('/pass/wallets/funds/$fundId');
return SnWalletFund.fromJson(resp.data);
}
@riverpod
Future<Map<String, dynamic>> walletFundStats(Ref ref) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/id/wallets/funds/stats');
final resp = await client.get('/pass/wallets/funds/stats');
return resp.data as Map<String, dynamic>;
}
@@ -563,7 +563,7 @@ class WalletScreen extends HookConsumerWidget {
Future<void> createWallet() async {
final client = ref.read(apiClientProvider);
try {
await client.post('/id/wallets');
await client.post('/pass/wallets');
ref.invalidate(walletCurrentProvider);
} catch (err) {
showErrorAlert(err);
@@ -941,14 +941,14 @@ class WalletScreen extends HookConsumerWidget {
try {
showLoadingModal(context);
final resp = await client.post(
'/id/wallets/funds',
'/pass/wallets/funds',
data: fundData,
options: Options(headers: {'X-Noop': true}),
);
final fund = SnWalletFund.fromJson(resp.data);
if (fund.status == 0) return; // Already created
final orderResp = await client.post('/id/wallets/funds/${fund.id}/order');
final orderResp = await client.post('/pass/wallets/funds/${fund.id}/order');
final order = SnWalletOrder.fromJson(orderResp.data);
if (context.mounted) hideLoadingModal(context);

View File

@@ -6,7 +6,7 @@ part of 'wallet.dart';
// RiverpodGenerator
// **************************************************************************
String _$walletCurrentHash() => r'088505ce1a78901016a3bda05217f813ed3b44c6';
String _$walletCurrentHash() => r'bdc7cb27ce2286b561a03522085cc4efc884faad';
/// See also [walletCurrent].
@ProviderFor(walletCurrent)
@@ -24,7 +24,7 @@ final walletCurrentProvider = AutoDisposeFutureProvider<SnWallet?>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef WalletCurrentRef = AutoDisposeFutureProviderRef<SnWallet?>;
String _$walletStatsHash() => r'23d692a922c2388135be6a46afa73c018762eb57';
String _$walletStatsHash() => r'2243011937b377a66cdf44cae144021cee69e82f';
/// See also [walletStats].
@ProviderFor(walletStats)
@@ -40,7 +40,7 @@ final walletStatsProvider = AutoDisposeFutureProvider<SnWalletStats>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef WalletStatsRef = AutoDisposeFutureProviderRef<SnWalletStats>;
String _$walletFundsHash() => r'7ceb415f64fcadab2b10461e27b95bf92352c707';
String _$walletFundsHash() => r'f60718c01ca5b7618a02682a0417669f750644a3';
/// Copied from Dart SDK
class _SystemHash {
@@ -195,7 +195,7 @@ class _WalletFundsProviderElement
}
String _$walletFundRecipientsHash() =>
r'18eb815eb709449dd5c545d81fc0ee43ca667578';
r'3a5e32b2d20700edd5944885693aff127b58adb1';
/// See also [walletFundRecipients].
@ProviderFor(walletFundRecipients)
@@ -339,7 +339,7 @@ class _WalletFundRecipientsProviderElement
int get take => (origin as WalletFundRecipientsProvider).take;
}
String _$walletFundHash() => r'a690b0def8f4293b4a8f244e44f8bb735687e5dd';
String _$walletFundHash() => r'459efdee5e2775eedaa4312e0d317c218fa7e1fa';
/// See also [walletFund].
@ProviderFor(walletFund)
@@ -460,7 +460,7 @@ class _WalletFundProviderElement
}
String _$transactionListNotifierHash() =>
r'7b777cd44f3351f68f7bd1dd76bfe8b388381bdb';
r'74d3c15f45a6e55b36150ab38e98475a508fc932';
/// See also [TransactionListNotifier].
@ProviderFor(TransactionListNotifier)

View File

@@ -13,14 +13,14 @@ class AbuseReportService {
Future<SnAbuseReport> getReport(String id) async {
final response = await ref
.read(apiClientProvider)
.get('/id/safety/reports/me/$id');
.get('/pass/safety/reports/me/$id');
return SnAbuseReport.fromJson(response.data);
}
Future<List<SnAbuseReport>> getReports() async {
final response = await ref
.read(apiClientProvider)
.get('/id/safety/reports/me');
.get('/pass/safety/reports/me');
return (response.data as List)
.map((json) => SnAbuseReport.fromJson(json))
.toList();

View File

@@ -0,0 +1,18 @@
import 'package:event_bus/event_bus.dart';
/// Global event bus instance for the application
final eventBus = EventBus();
/// Event fired when a post is successfully created
class PostCreatedEvent {
final String? postId;
final String? title;
final String? content;
const PostCreatedEvent({this.postId, this.title, this.content});
}
/// Event fired when chat rooms need to be refreshed
class ChatRoomsRefreshEvent {
const ChatRoomsRefreshEvent();
}

View File

@@ -22,7 +22,7 @@ part 'account_devices.g.dart';
Future<List<SnAuthDeviceWithChallenge>> authDevices(Ref ref) async {
final resp = await ref
.watch(apiClientProvider)
.get('/id/accounts/me/devices');
.get('/pass/accounts/me/devices');
final currentId = await getUdid();
final data =
resp.data.map<SnAuthDeviceWithChallenge>((e) {
@@ -154,7 +154,7 @@ class AccountSessionSheet extends HookConsumerWidget {
if (!confirm || !context.mounted) return;
try {
final apiClient = ref.watch(apiClientProvider);
await apiClient.delete('/id/accounts/me/devices/$sessionId');
await apiClient.delete('/pass/accounts/me/devices/$sessionId');
ref.invalidate(authDevicesProvider);
} catch (err) {
showErrorAlert(err);
@@ -193,7 +193,7 @@ class AccountSessionSheet extends HookConsumerWidget {
try {
final apiClient = ref.watch(apiClientProvider);
await apiClient.patch(
'/id/accounts/me/devices/$sessionId/label',
'/pass/accounts/me/devices/$sessionId/label',
data: jsonEncode(label),
);
ref.invalidate(authDevicesProvider);
@@ -284,7 +284,7 @@ class AccountSessionSheet extends HookConsumerWidget {
apiClientProvider,
);
await apiClient.delete(
'/id/accounts/me/devices/${device.deviceId}',
'/pass/accounts/me/devices/${device.deviceId}',
);
ref.invalidate(authDevicesProvider);
} catch (err) {

Some files were not shown because too many files have changed in this diff Show More