Compare commits
52 Commits
refactor/w
...
features/w
| Author | SHA1 | Date | |
|---|---|---|---|
|
f47e7f1d50
|
|||
|
76e7ba7898
|
|||
|
6e6616b236
|
|||
|
071d51b25e
|
|||
|
a958362461
|
|||
|
6749bb00fe
|
|||
|
11fb20c673
|
|||
|
a7990f83db
|
|||
|
5f4cdf7937
|
|||
|
3330ca14dd
|
|||
|
1719b1c8fe
|
|||
|
3c2c51bfaf
|
|||
|
239d6750ff
|
|||
|
8b0c91977a
|
|||
|
f74cca8464
|
|||
|
08091d51bf
|
|||
|
481190811b
|
|||
|
4b32b65d1c
|
|||
|
50ac7109bb
|
|||
|
62da279c71
|
|||
|
fde6dbf891
|
|||
|
613bf4fb42
|
|||
|
00ae586016
|
|||
|
ea0d132dce
|
|||
|
aa2df1e847
|
|||
|
50672795f3
|
|||
|
383de9568d
|
|||
|
01fa228e45
|
|||
|
1e71ad33a6
|
|||
|
92c0260ecd
|
|||
|
0a161ad255
|
|||
|
c003f27b9a
|
|||
|
19db8309c4
|
|||
|
aa72ce08e8
|
|||
|
4639b00b86
|
|||
|
cc5460ea55
|
|||
|
eafac811e6
|
|||
|
e3be691596
|
|||
|
aa180a1358
|
|||
|
c2707b8af1
|
|||
|
62fd0500f3
|
|||
|
eeae865cc8
|
|||
|
cdf1413fe0
|
|||
|
327b4c04f1
|
|||
|
bd903ce29c
|
|||
|
1b8ecb15ce
|
|||
|
d4e380a97a
|
|||
|
126048b4fa
|
|||
|
8bec18813d
|
|||
|
1ae81794b1
|
|||
|
2a7d12de48
|
|||
|
64c60ead48
|
@@ -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"
|
||||
}
|
||||
|
||||
@@ -1081,5 +1081,14 @@
|
||||
"postPublish": "发布帖子",
|
||||
"restoreDraftTitle": "恢复草稿",
|
||||
"restoreDraftMessage": "发现了一个草稿。你想要恢复它吗?",
|
||||
"draft": "草稿"
|
||||
"draft": "草稿",
|
||||
"thoughtDefaultTopic": "寻思",
|
||||
"thoughtAiName": "SN 酱",
|
||||
"thoughtUserName": "您",
|
||||
"thoughtStreamingHint": "SN 酱正在思考...",
|
||||
"thoughtInputHint": "问 SN 酱任何问题...",
|
||||
"thoughtNewConversation": "开始新对话",
|
||||
"thoughtParseError": "解析 AI 响应失败",
|
||||
"aiThought": "寻思",
|
||||
"aiThoughtTitle": "让 SN 酱寻思寻思"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ PODS:
|
||||
- Alamofire (5.10.2)
|
||||
- app_links (6.4.1):
|
||||
- Flutter
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- croppy (0.0.1):
|
||||
- Flutter
|
||||
- device_info_plus (0.0.1):
|
||||
@@ -217,6 +219,10 @@ PODS:
|
||||
- irondash_engine_context (0.0.1):
|
||||
- Flutter
|
||||
- Kingfisher (8.6.0)
|
||||
- livekit_client (2.5.3):
|
||||
- Flutter
|
||||
- flutter_webrtc
|
||||
- WebRTC-SDK (= 137.7151.04)
|
||||
- local_auth_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
@@ -303,6 +309,7 @@ PODS:
|
||||
DEPENDENCIES:
|
||||
- Alamofire
|
||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
@@ -326,6 +333,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)
|
||||
- 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`)
|
||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
||||
@@ -380,6 +388,8 @@ SPEC REPOS:
|
||||
EXTERNAL SOURCES:
|
||||
app_links:
|
||||
:path: ".symlinks/plugins/app_links/ios"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
croppy:
|
||||
:path: ".symlinks/plugins/croppy/ios"
|
||||
device_info_plus:
|
||||
@@ -424,6 +434,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
irondash_engine_context:
|
||||
:path: ".symlinks/plugins/irondash_engine_context/ios"
|
||||
livekit_client:
|
||||
:path: ".symlinks/plugins/livekit_client/ios"
|
||||
local_auth_darwin:
|
||||
:path: ".symlinks/plugins/local_auth_darwin/darwin"
|
||||
media_kit_libs_ios_video:
|
||||
@@ -468,6 +480,7 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
||||
app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
@@ -504,9 +517,10 @@ SPEC CHECKSUMS:
|
||||
GoogleAppMeasurement: 1e718274b7e015cefd846ac1fcf7820c70dc017d
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
||||
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
||||
Kingfisher: 64278f126a815d0e2d391cdf71311b85882c4de0
|
||||
livekit_client: 86c8af579274e4b7a215185a8080db2d4e176f40
|
||||
local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb
|
||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||
@@ -515,8 +529,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
|
||||
@@ -524,7 +538,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
|
||||
@@ -532,7 +546,7 @@ 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 77;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -15,6 +15,7 @@
|
||||
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
73CDD6812DEC00480059D95D /* SolianNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
73D4264B2DEB815D006C0AAE /* NotifyDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D4264A2DEB815D006C0AAE /* NotifyDelegate.swift */; };
|
||||
73FFBFC72EAFE896001C559B /* WatchRunner Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 73FFBFBD2EAFE894001C559B /* WatchRunner Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
755557017FD1B99AFC4F9127 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29812C17FFBE7DBBC7203981 /* Pods_RunnerTests.framework */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
@@ -55,6 +56,13 @@
|
||||
remoteGlobalIDString = 73CDD6792DEC00480059D95D;
|
||||
remoteInfo = SolianNotificationService;
|
||||
};
|
||||
73FFBFC52EAFE896001C559B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 73FFBFBC2EAFE894001C559B;
|
||||
remoteInfo = "WatchRunner Watch App";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -71,6 +79,17 @@
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
73FFBFC82EAFE896001C559B /* Embed Watch Content */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
73FFBFC72EAFE896001C559B /* WatchRunner Watch App.app in Embed Watch Content */,
|
||||
);
|
||||
name = "Embed Watch Content";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -107,6 +126,7 @@
|
||||
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianNotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
73D4264A2DEB815D006C0AAE /* NotifyDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyDelegate.swift; sourceTree = "<group>"; };
|
||||
73FFBFBD2EAFE894001C559B /* WatchRunner Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WatchRunner Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
@@ -194,6 +214,11 @@
|
||||
path = SolianNotificationService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
73FFBFBE2EAFE894001C559B /* WatchRunner Watch App */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
path = "WatchRunner Watch App";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -229,6 +254,13 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
73FFBFBA2EAFE894001C559B /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -303,6 +335,7 @@
|
||||
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
|
||||
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
|
||||
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||
73FFBFBE2EAFE894001C559B /* WatchRunner Watch App */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
91E124CE95BCB4DCD890160D /* Pods */,
|
||||
@@ -319,6 +352,7 @@
|
||||
73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */,
|
||||
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
|
||||
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
|
||||
73FFBFBD2EAFE894001C559B /* WatchRunner Watch App.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -425,6 +459,28 @@
|
||||
productReference = 73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
73FFBFBC2EAFE894001C559B /* WatchRunner Watch App */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 73FFBFCC2EAFE896001C559B /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */;
|
||||
buildPhases = (
|
||||
73FFBFB92EAFE894001C559B /* Sources */,
|
||||
73FFBFBA2EAFE894001C559B /* Frameworks */,
|
||||
73FFBFBB2EAFE894001C559B /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
73FFBFBE2EAFE894001C559B /* WatchRunner Watch App */,
|
||||
);
|
||||
name = "WatchRunner Watch App";
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = "WatchRunner Watch App";
|
||||
productReference = 73FFBFBD2EAFE894001C559B /* WatchRunner Watch App.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
@@ -440,6 +496,7 @@
|
||||
8C0351B03869BBF493808288 /* [CP] Embed Pods Frameworks */,
|
||||
5E7D6EF29B671AC7EDBA5649 /* [CP] Copy Pods Resources */,
|
||||
E86CDE9D6464F4F52B910856 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
|
||||
73FFBFC82EAFE896001C559B /* Embed Watch Content */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -447,6 +504,7 @@
|
||||
73CDD6802DEC00480059D95D /* PBXTargetDependency */,
|
||||
73C305D72E0BE878009035B9 /* PBXTargetDependency */,
|
||||
73ACDFC22E3D0E6100B63535 /* PBXTargetDependency */,
|
||||
73FFBFC62EAFE896001C559B /* PBXTargetDependency */,
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
73268D272DEB012A0076E970 /* Services */,
|
||||
@@ -463,7 +521,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 1640;
|
||||
LastSwiftUpdateCheck = 2600;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
@@ -480,6 +538,9 @@
|
||||
73CDD6792DEC00480059D95D = {
|
||||
CreatedOnToolsVersion = 16.4;
|
||||
};
|
||||
73FFBFBC2EAFE894001C559B = {
|
||||
CreatedOnToolsVersion = 26.0.1;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
@@ -504,6 +565,7 @@
|
||||
73CDD6792DEC00480059D95D /* SolianNotificationService */,
|
||||
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
|
||||
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||
73FFBFBC2EAFE894001C559B /* WatchRunner Watch App */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -537,6 +599,13 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
73FFBFBB2EAFE894001C559B /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -598,10 +667,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 +732,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";
|
||||
@@ -755,6 +832,13 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
73FFBFB92EAFE894001C559B /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -788,6 +872,11 @@
|
||||
target = 73CDD6792DEC00480059D95D /* SolianNotificationService */;
|
||||
targetProxy = 73CDD67F2DEC00480059D95D /* PBXContainerItemProxy */;
|
||||
};
|
||||
73FFBFC62EAFE896001C559B /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 73FFBFBC2EAFE894001C559B /* WatchRunner Watch App */;
|
||||
targetProxy = 73FFBFC52EAFE896001C559B /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
@@ -1306,6 +1395,141 @@
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
73FFBFC92EAFE896001C559B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
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 = YES;
|
||||
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;
|
||||
};
|
||||
73FFBFCA2EAFE896001C559B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
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 = YES;
|
||||
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;
|
||||
};
|
||||
73FFBFCB2EAFE896001C559B /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
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 = YES;
|
||||
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;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -1517,6 +1741,16 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
73FFBFCC2EAFE896001C559B /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
73FFBFC92EAFE896001C559B /* Debug */,
|
||||
73FFBFCA2EAFE896001C559B /* Release */,
|
||||
73FFBFCB2EAFE896001C559B /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"platform" : "watchos",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
6
ios/WatchRunner Watch App/Assets.xcassets/Contents.json
Normal file
6
ios/WatchRunner Watch App/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
24
ios/WatchRunner Watch App/ContentView.swift
Normal file
24
ios/WatchRunner Watch App/ContentView.swift
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// WatchRunner Watch App
|
||||
//
|
||||
// Created by LittleSheep on 2025/10/28.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
Image(systemName: "globe")
|
||||
.imageScale(.large)
|
||||
.foregroundStyle(.tint)
|
||||
Text("Hello, world!")
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
}
|
||||
17
ios/WatchRunner Watch App/WatchRunnerApp.swift
Normal file
17
ios/WatchRunner Watch App/WatchRunnerApp.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,8 +149,6 @@ sealed class CallParticipant with _$CallParticipant {
|
||||
const factory CallParticipant({
|
||||
required String identity,
|
||||
required String name,
|
||||
required String accountId,
|
||||
@Default(null) SnAccount? account,
|
||||
required DateTime joinedAt,
|
||||
}) = _CallParticipant;
|
||||
|
||||
|
||||
@@ -2241,7 +2241,7 @@ as List<CallParticipant>,
|
||||
/// @nodoc
|
||||
mixin _$CallParticipant {
|
||||
|
||||
String get identity; String get name; String get accountId; SnAccount? get account; DateTime get joinedAt;
|
||||
String get identity; String get name; DateTime get joinedAt;
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -2254,16 +2254,16 @@ $CallParticipantCopyWith<CallParticipant> get copyWith => _$CallParticipantCopyW
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallParticipant&&(identical(other.identity, identity) || other.identity == identity)&&(identical(other.name, name) || other.name == name)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallParticipant&&(identical(other.identity, identity) || other.identity == identity)&&(identical(other.name, name) || other.name == name)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,identity,name,accountId,account,joinedAt);
|
||||
int get hashCode => Object.hash(runtimeType,identity,name,joinedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallParticipant(identity: $identity, name: $name, accountId: $accountId, account: $account, joinedAt: $joinedAt)';
|
||||
return 'CallParticipant(identity: $identity, name: $name, joinedAt: $joinedAt)';
|
||||
}
|
||||
|
||||
|
||||
@@ -2274,11 +2274,11 @@ abstract mixin class $CallParticipantCopyWith<$Res> {
|
||||
factory $CallParticipantCopyWith(CallParticipant value, $Res Function(CallParticipant) _then) = _$CallParticipantCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String identity, String name, String accountId, SnAccount? account, DateTime joinedAt
|
||||
String identity, String name, DateTime joinedAt
|
||||
});
|
||||
|
||||
|
||||
$SnAccountCopyWith<$Res>? get account;
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -2291,29 +2291,15 @@ class _$CallParticipantCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? identity = null,Object? name = null,Object? accountId = null,Object? account = freezed,Object? joinedAt = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? identity = null,Object? name = null,Object? joinedAt = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
identity: null == identity ? _self.identity : identity // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: null == name ? _self.name : name // 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?,joinedAt: null == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
|
||||
as String,joinedAt: null == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
));
|
||||
}
|
||||
/// Create a copy of CallParticipant
|
||||
/// 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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2392,10 +2378,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String identity, String name, String accountId, SnAccount? account, DateTime joinedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String identity, String name, DateTime joinedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallParticipant() when $default != null:
|
||||
return $default(_that.identity,_that.name,_that.accountId,_that.account,_that.joinedAt);case _:
|
||||
return $default(_that.identity,_that.name,_that.joinedAt);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -2413,10 +2399,10 @@ return $default(_that.identity,_that.name,_that.accountId,_that.account,_that.jo
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String identity, String name, String accountId, SnAccount? account, DateTime joinedAt) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String identity, String name, DateTime joinedAt) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallParticipant():
|
||||
return $default(_that.identity,_that.name,_that.accountId,_that.account,_that.joinedAt);}
|
||||
return $default(_that.identity,_that.name,_that.joinedAt);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -2430,10 +2416,10 @@ return $default(_that.identity,_that.name,_that.accountId,_that.account,_that.jo
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String identity, String name, String accountId, SnAccount? account, DateTime joinedAt)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String identity, String name, DateTime joinedAt)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallParticipant() when $default != null:
|
||||
return $default(_that.identity,_that.name,_that.accountId,_that.account,_that.joinedAt);case _:
|
||||
return $default(_that.identity,_that.name,_that.joinedAt);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -2445,13 +2431,11 @@ return $default(_that.identity,_that.name,_that.accountId,_that.account,_that.jo
|
||||
@JsonSerializable()
|
||||
|
||||
class _CallParticipant implements CallParticipant {
|
||||
const _CallParticipant({required this.identity, required this.name, required this.accountId, this.account = null, required this.joinedAt});
|
||||
const _CallParticipant({required this.identity, required this.name, required this.joinedAt});
|
||||
factory _CallParticipant.fromJson(Map<String, dynamic> json) => _$CallParticipantFromJson(json);
|
||||
|
||||
@override final String identity;
|
||||
@override final String name;
|
||||
@override final String accountId;
|
||||
@override@JsonKey() final SnAccount? account;
|
||||
@override final DateTime joinedAt;
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
@@ -2467,16 +2451,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallParticipant&&(identical(other.identity, identity) || other.identity == identity)&&(identical(other.name, name) || other.name == name)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallParticipant&&(identical(other.identity, identity) || other.identity == identity)&&(identical(other.name, name) || other.name == name)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,identity,name,accountId,account,joinedAt);
|
||||
int get hashCode => Object.hash(runtimeType,identity,name,joinedAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CallParticipant(identity: $identity, name: $name, accountId: $accountId, account: $account, joinedAt: $joinedAt)';
|
||||
return 'CallParticipant(identity: $identity, name: $name, joinedAt: $joinedAt)';
|
||||
}
|
||||
|
||||
|
||||
@@ -2487,11 +2471,11 @@ abstract mixin class _$CallParticipantCopyWith<$Res> implements $CallParticipant
|
||||
factory _$CallParticipantCopyWith(_CallParticipant value, $Res Function(_CallParticipant) _then) = __$CallParticipantCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String identity, String name, String accountId, SnAccount? account, DateTime joinedAt
|
||||
String identity, String name, DateTime joinedAt
|
||||
});
|
||||
|
||||
|
||||
@override $SnAccountCopyWith<$Res>? get account;
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -2504,30 +2488,16 @@ class __$CallParticipantCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? identity = null,Object? name = null,Object? accountId = null,Object? account = freezed,Object? joinedAt = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? identity = null,Object? name = null,Object? joinedAt = null,}) {
|
||||
return _then(_CallParticipant(
|
||||
identity: null == identity ? _self.identity : identity // ignore: cast_nullable_to_non_nullable
|
||||
as String,name: null == name ? _self.name : name // 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?,joinedAt: null == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
|
||||
as String,joinedAt: null == joinedAt ? _self.joinedAt : joinedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of CallParticipant
|
||||
/// 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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -275,11 +275,6 @@ _CallParticipant _$CallParticipantFromJson(Map<String, dynamic> json) =>
|
||||
_CallParticipant(
|
||||
identity: json['identity'] as String,
|
||||
name: json['name'] as String,
|
||||
accountId: json['account_id'] as String,
|
||||
account:
|
||||
json['account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||
joinedAt: DateTime.parse(json['joined_at'] as String),
|
||||
);
|
||||
|
||||
@@ -287,8 +282,6 @@ Map<String, dynamic> _$CallParticipantToJson(_CallParticipant instance) =>
|
||||
<String, dynamic>{
|
||||
'identity': instance.identity,
|
||||
'name': instance.name,
|
||||
'account_id': instance.accountId,
|
||||
'account': instance.account?.toJson(),
|
||||
'joined_at': instance.joinedAt.toIso8601String(),
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
116
lib/models/thought.dart
Normal 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);
|
||||
}
|
||||
1177
lib/models/thought.freezed.dart
Normal file
1177
lib/models/thought.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
128
lib/models/thought.g.dart
Normal file
128
lib/models/thought.g.dart
Normal 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(),
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
@@ -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},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,13 @@ import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/chat/call_button.dart';
|
||||
import 'package:livekit_client/livekit_client.dart' as lk;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/models/chat.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/pods/chat/webrtc_manager.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
import 'package:island/talker.dart';
|
||||
|
||||
@@ -45,212 +43,193 @@ sealed class CallParticipantLive with _$CallParticipantLive {
|
||||
|
||||
const factory CallParticipantLive({
|
||||
required CallParticipant participant,
|
||||
required WebRTCParticipant remoteParticipant,
|
||||
required lk.Participant remoteParticipant,
|
||||
}) = _CallParticipantLive;
|
||||
|
||||
bool get isSpeaking {
|
||||
// Use the actual audio level from WebRTC monitoring
|
||||
return remoteParticipant.audioLevel > 0.1; // Threshold for speaking
|
||||
}
|
||||
bool get isSpeaking => remoteParticipant.isSpeaking;
|
||||
bool get isMuted =>
|
||||
remoteParticipant.isMuted || !remoteParticipant.isMicrophoneEnabled();
|
||||
bool get isScreenSharing => remoteParticipant.isScreenShareEnabled();
|
||||
bool get isScreenSharingWithAudio =>
|
||||
remoteParticipant.isScreenShareAudioEnabled();
|
||||
|
||||
double get audioLevel => remoteParticipant.audioLevel;
|
||||
|
||||
bool get isMuted => !remoteParticipant.isAudioEnabled;
|
||||
bool get isScreenSharing => remoteParticipant.isVideoEnabled; // Simplified
|
||||
bool get isScreenSharingWithAudio => false; // TODO: Implement screen sharing
|
||||
|
||||
bool get hasVideo => remoteParticipant.isVideoEnabled;
|
||||
bool get hasAudio => remoteParticipant.isAudioEnabled;
|
||||
bool get hasVideo => remoteParticipant.hasVideo;
|
||||
bool get hasAudio => remoteParticipant.hasAudio;
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class CallNotifier extends _$CallNotifier {
|
||||
WebRTCManager? _webrtcManager;
|
||||
lk.Room? _room;
|
||||
lk.LocalParticipant? _localParticipant;
|
||||
List<CallParticipantLive> _participants = [];
|
||||
final Map<String, CallParticipant> _participantInfoByIdentity = {};
|
||||
StreamSubscription<WebRTCParticipant>? _participantJoinedSubscription;
|
||||
StreamSubscription<String>? _participantLeftSubscription;
|
||||
lk.EventsListener? _roomListener;
|
||||
|
||||
List<CallParticipantLive> get participants =>
|
||||
List.unmodifiable(_participants);
|
||||
lk.LocalParticipant? get localParticipant => _localParticipant;
|
||||
|
||||
Map<String, double> participantsVolumes = {};
|
||||
|
||||
Timer? _durationTimer;
|
||||
|
||||
String? _roomId;
|
||||
String? get roomId => _roomId;
|
||||
WebRTCManager? get webrtcManager => _webrtcManager;
|
||||
lk.Room? get room => _room;
|
||||
|
||||
@override
|
||||
CallState build() {
|
||||
// Subscribe to websocket updates
|
||||
return const CallState(
|
||||
isConnected: false,
|
||||
isMicrophoneEnabled:
|
||||
true, // Audio enabled by default (matches WebRTC init)
|
||||
isCameraEnabled: true, // Video enabled by default (matches WebRTC init)
|
||||
isMicrophoneEnabled: true,
|
||||
isCameraEnabled: false,
|
||||
isScreenSharing: false,
|
||||
isSpeakerphone: true,
|
||||
);
|
||||
}
|
||||
|
||||
void _initWebRTCListeners() {
|
||||
_participantJoinedSubscription?.cancel();
|
||||
_participantLeftSubscription?.cancel();
|
||||
|
||||
_participantJoinedSubscription = _webrtcManager?.onParticipantJoined.listen(
|
||||
(participant) {
|
||||
_updateLiveParticipantsFromWebRTC();
|
||||
},
|
||||
);
|
||||
|
||||
_participantLeftSubscription = _webrtcManager?.onParticipantLeft.listen((
|
||||
participantId,
|
||||
) {
|
||||
_participants.removeWhere((p) => p.remoteParticipant.id == participantId);
|
||||
state = state.copyWith();
|
||||
});
|
||||
|
||||
// Add local participant immediately when WebRTC is initialized
|
||||
final userinfo = ref.watch(userInfoProvider);
|
||||
if (userinfo.value != null) {
|
||||
_addLocalParticipant(userinfo.value!);
|
||||
}
|
||||
void _initRoomListeners() {
|
||||
if (_room == null) return;
|
||||
_roomListener?.dispose();
|
||||
_roomListener = _room!.createListener();
|
||||
_room!.addListener(_onRoomChange);
|
||||
_roomListener!
|
||||
..on<lk.ParticipantConnectedEvent>((e) {
|
||||
_refreshLiveParticipants();
|
||||
})
|
||||
..on<lk.RoomDisconnectedEvent>((e) {
|
||||
_participants = [];
|
||||
state = state.copyWith();
|
||||
});
|
||||
}
|
||||
|
||||
void _addLocalParticipant(SnAccount userinfo) {
|
||||
if (_webrtcManager == null) return;
|
||||
|
||||
// Remove any existing local participant first
|
||||
_participants.removeWhere((p) => p.participant.identity == userinfo.id);
|
||||
|
||||
// Add local participant (current user)
|
||||
final localParticipant = CallParticipantLive(
|
||||
participant: CallParticipant(
|
||||
identity: userinfo.id, // Use roomId as local identity
|
||||
name: userinfo.name,
|
||||
accountId: userinfo.id,
|
||||
account: userinfo,
|
||||
joinedAt: DateTime.now(),
|
||||
),
|
||||
remoteParticipant: WebRTCParticipant(
|
||||
id: _webrtcManager!.roomId,
|
||||
name: userinfo.nick,
|
||||
userinfo: userinfo,
|
||||
isLocal: true,
|
||||
)..remoteStream = _webrtcManager!.localStream, // Access local stream
|
||||
);
|
||||
|
||||
_participants.insert(0, localParticipant); // Add at the beginning
|
||||
state = state.copyWith();
|
||||
void _onRoomChange() {
|
||||
_refreshLiveParticipants();
|
||||
}
|
||||
|
||||
void _updateLiveParticipantsFromWebRTC() {
|
||||
if (_webrtcManager == null) return;
|
||||
|
||||
final webrtcParticipants = _webrtcManager!.participants;
|
||||
|
||||
// Always ensure local participant exists
|
||||
final existingLocalParticipant =
|
||||
_participants.isNotEmpty &&
|
||||
_participants[0].remoteParticipant.id == _webrtcManager!.roomId
|
||||
? _participants[0]
|
||||
: null;
|
||||
|
||||
final localParticipant =
|
||||
existingLocalParticipant ?? _createLocalParticipant();
|
||||
|
||||
// Add remote participants
|
||||
final remoteParticipants =
|
||||
webrtcParticipants.map((p) {
|
||||
final participantInfo =
|
||||
_participantInfoByIdentity[p.id] ??
|
||||
CallParticipant(
|
||||
identity: p.id,
|
||||
name: p.name,
|
||||
accountId: p.userinfo.id,
|
||||
account: p.userinfo,
|
||||
joinedAt: DateTime.now(),
|
||||
);
|
||||
return CallParticipantLive(
|
||||
participant: participantInfo,
|
||||
remoteParticipant: p,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
// Combine local participant with remote participants
|
||||
_participants = [localParticipant, ...remoteParticipants];
|
||||
|
||||
state = state.copyWith();
|
||||
}
|
||||
|
||||
CallParticipantLive _createLocalParticipant() {
|
||||
return CallParticipantLive(
|
||||
participant: CallParticipant(
|
||||
identity: _webrtcManager!.roomId, // Use roomId as local identity
|
||||
name: 'You',
|
||||
accountId: '',
|
||||
account: null,
|
||||
joinedAt: DateTime.now(),
|
||||
),
|
||||
remoteParticipant: WebRTCParticipant(
|
||||
id: _webrtcManager!.roomId,
|
||||
name: 'You',
|
||||
userinfo: SnAccount(
|
||||
id: '',
|
||||
name: '',
|
||||
nick: '',
|
||||
language: '',
|
||||
isSuperuser: false,
|
||||
automatedId: null,
|
||||
profile: SnAccountProfile(
|
||||
id: '',
|
||||
firstName: '',
|
||||
middleName: '',
|
||||
lastName: '',
|
||||
bio: '',
|
||||
gender: '',
|
||||
pronouns: '',
|
||||
location: '',
|
||||
timeZone: '',
|
||||
links: [],
|
||||
experience: 0,
|
||||
level: 0,
|
||||
socialCredits: 0,
|
||||
socialCreditsLevel: 0,
|
||||
levelingProgress: 0,
|
||||
picture: null,
|
||||
background: null,
|
||||
verification: null,
|
||||
usernameColor: null,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
deletedAt: null,
|
||||
),
|
||||
perkSubscription: null,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
deletedAt: null,
|
||||
void _refreshLiveParticipants() {
|
||||
if (_room == null) return;
|
||||
final remoteParticipants = _room!.remoteParticipants;
|
||||
_participants = [];
|
||||
// Add local participant first if available
|
||||
if (_localParticipant != null) {
|
||||
final localInfo = _buildParticipant();
|
||||
_participants.add(
|
||||
CallParticipantLive(
|
||||
participant: localInfo,
|
||||
remoteParticipant: _localParticipant!,
|
||||
),
|
||||
)..remoteStream = _webrtcManager!.localStream, // Access local stream
|
||||
);
|
||||
}
|
||||
// Add remote participants
|
||||
_participants.addAll(
|
||||
remoteParticipants.values.map((remote) {
|
||||
final match =
|
||||
_participantInfoByIdentity[remote.identity] ??
|
||||
CallParticipant(
|
||||
identity: remote.identity,
|
||||
name: remote.identity,
|
||||
joinedAt: DateTime.now(),
|
||||
);
|
||||
return CallParticipantLive(
|
||||
participant: match,
|
||||
remoteParticipant: remote,
|
||||
);
|
||||
}),
|
||||
);
|
||||
state = state.copyWith();
|
||||
}
|
||||
|
||||
Future<void> joinRoom(String roomId) async {
|
||||
if (_roomId == roomId && _webrtcManager != null) {
|
||||
talker.info('[Call] Call skipped. Already connected to this room');
|
||||
// Ensure state is connected even if we skip the join process
|
||||
if (!state.isConnected) {
|
||||
state = state.copyWith(isConnected: true);
|
||||
}
|
||||
/// Builds the CallParticipant object for the local participant.
|
||||
/// Optionally, pass [participants] if you want to prioritize info from the latest list.
|
||||
CallParticipant _buildParticipant({List<CallParticipant>? participants}) {
|
||||
if (_localParticipant == null) {
|
||||
throw StateError('No local participant available');
|
||||
}
|
||||
// Prefer info from the latest participants list if available
|
||||
if (participants != null) {
|
||||
final idx = participants.indexWhere(
|
||||
(p) => p.identity == _localParticipant!.identity,
|
||||
);
|
||||
if (idx != -1) return participants[idx];
|
||||
}
|
||||
|
||||
// Otherwise, use info from the identity map or fallback to minimal
|
||||
return _participantInfoByIdentity[_localParticipant!.identity] ??
|
||||
CallParticipant(
|
||||
identity: _localParticipant!.identity,
|
||||
name: _localParticipant!.identity,
|
||||
joinedAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateLiveParticipants(List<CallParticipant> participants) {
|
||||
// Update the info map for lookup
|
||||
for (final p in participants) {
|
||||
_participantInfoByIdentity[p.identity] = p;
|
||||
}
|
||||
if (_room == null) {
|
||||
// Can't build live objects, just store empty
|
||||
_participants = [];
|
||||
state = state.copyWith();
|
||||
return;
|
||||
}
|
||||
final remoteParticipants = _room!.remoteParticipants;
|
||||
final remotes = remoteParticipants.values.toList();
|
||||
_participants = [];
|
||||
// Add local participant if present in the list
|
||||
if (_localParticipant != null) {
|
||||
final localInfo = _buildParticipant(participants: participants);
|
||||
_participants.add(
|
||||
CallParticipantLive(
|
||||
participant: localInfo,
|
||||
remoteParticipant: _localParticipant!,
|
||||
),
|
||||
);
|
||||
state = state.copyWith();
|
||||
}
|
||||
// Add remote participants
|
||||
_participants.addAll(
|
||||
participants.map((p) {
|
||||
lk.RemoteParticipant? remote;
|
||||
for (final r in remotes) {
|
||||
if (r.identity == p.identity) {
|
||||
remote = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_localParticipant != null &&
|
||||
p.identity == _localParticipant!.identity) {
|
||||
return null; // Already added local
|
||||
}
|
||||
return remote != null
|
||||
? CallParticipantLive(participant: p, remoteParticipant: remote)
|
||||
: null;
|
||||
}).whereType<CallParticipantLive>(),
|
||||
);
|
||||
state = state.copyWith();
|
||||
}
|
||||
|
||||
String? _roomId;
|
||||
String? get roomId => _roomId;
|
||||
|
||||
Future<void> joinRoom(String roomId) async {
|
||||
if (_roomId == roomId && _room != null) {
|
||||
talker.info('[Call] Call skipped. Already has data');
|
||||
return;
|
||||
} else if (_room != null) {
|
||||
if (!_room!.isDisposed &&
|
||||
_room!.connectionState != lk.ConnectionState.disconnected) {
|
||||
throw Exception('Call already connected');
|
||||
}
|
||||
}
|
||||
_roomId = roomId;
|
||||
|
||||
// Clean up existing connection
|
||||
await disconnect();
|
||||
|
||||
if (_room != null) {
|
||||
await _room!.disconnect();
|
||||
await _room!.dispose();
|
||||
_room = null;
|
||||
_localParticipant = null;
|
||||
_participants = [];
|
||||
}
|
||||
try {
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final ongoingCall = await ref.read(ongoingCallProvider(roomId).future);
|
||||
@@ -262,11 +241,8 @@ class CallNotifier extends _$CallNotifier {
|
||||
// Parse join response
|
||||
final joinResponse = ChatRealtimeJoinResponse.fromJson(data);
|
||||
final participants = joinResponse.participants;
|
||||
|
||||
// Update participant info map
|
||||
for (final p in participants) {
|
||||
_participantInfoByIdentity[p.identity] = p;
|
||||
}
|
||||
final String endpoint = joinResponse.endpoint;
|
||||
final String token = joinResponse.token;
|
||||
|
||||
// Setup duration timer
|
||||
_durationTimer?.cancel();
|
||||
@@ -281,18 +257,47 @@ class CallNotifier extends _$CallNotifier {
|
||||
);
|
||||
});
|
||||
|
||||
// Initialize WebRTC manager
|
||||
final serverUrl = ref.watch(serverUrlProvider);
|
||||
// Connect to LiveKit
|
||||
_room = lk.Room();
|
||||
|
||||
_webrtcManager = WebRTCManager(roomId: roomId, serverUrl: serverUrl);
|
||||
await _room!.connect(
|
||||
endpoint,
|
||||
token,
|
||||
connectOptions: lk.ConnectOptions(autoSubscribe: true),
|
||||
roomOptions: lk.RoomOptions(adaptiveStream: true, dynacast: true),
|
||||
fastConnectOptions: lk.FastConnectOptions(
|
||||
microphone: lk.TrackOption(enabled: true),
|
||||
),
|
||||
);
|
||||
_localParticipant = _room!.localParticipant;
|
||||
|
||||
await _webrtcManager!.initialize(ref);
|
||||
_initWebRTCListeners();
|
||||
_initRoomListeners();
|
||||
_updateLiveParticipants(participants);
|
||||
|
||||
if (!kIsWeb && (Platform.isIOS || Platform.isAndroid)) {
|
||||
// TODO: Implement speakerphone control for WebRTC
|
||||
lk.Hardware.instance.setSpeakerphoneOn(true);
|
||||
}
|
||||
|
||||
// Listen for connection updates
|
||||
_room!.addListener(() {
|
||||
final wasConnected = state.isConnected;
|
||||
final isNowConnected =
|
||||
_room!.connectionState == lk.ConnectionState.connected;
|
||||
state = state.copyWith(
|
||||
isConnected: isNowConnected,
|
||||
isMicrophoneEnabled: _localParticipant!.isMicrophoneEnabled(),
|
||||
isCameraEnabled: _localParticipant!.isCameraEnabled(),
|
||||
isScreenSharing: _localParticipant!.isScreenShareEnabled(),
|
||||
);
|
||||
// Enable wakelock when call connects
|
||||
if (!wasConnected && isNowConnected) {
|
||||
WakelockPlus.enable();
|
||||
}
|
||||
// Disable wakelock when call disconnects
|
||||
else if (wasConnected && !isNowConnected) {
|
||||
WakelockPlus.disable();
|
||||
}
|
||||
});
|
||||
state = state.copyWith(isConnected: true);
|
||||
// Enable wakelock when call connects
|
||||
WakelockPlus.enable();
|
||||
@@ -305,114 +310,104 @@ class CallNotifier extends _$CallNotifier {
|
||||
}
|
||||
|
||||
Future<void> toggleMicrophone() async {
|
||||
final target = !state.isMicrophoneEnabled;
|
||||
state = state.copyWith(isMicrophoneEnabled: target);
|
||||
await _webrtcManager?.toggleMicrophone(target);
|
||||
|
||||
// Update local participant's audio state
|
||||
if (_participants.isNotEmpty) {
|
||||
_participants[0].remoteParticipant.isAudioEnabled = target;
|
||||
state = state.copyWith(); // Trigger UI update
|
||||
if (_localParticipant != null) {
|
||||
const autostop = true;
|
||||
final target = !_localParticipant!.isMicrophoneEnabled();
|
||||
state = state.copyWith(isMicrophoneEnabled: target);
|
||||
if (target) {
|
||||
await _localParticipant!.audioTrackPublications.firstOrNull?.unmute(
|
||||
stopOnMute: autostop,
|
||||
);
|
||||
} else {
|
||||
await _localParticipant!.audioTrackPublications.firstOrNull?.mute(
|
||||
stopOnMute: autostop,
|
||||
);
|
||||
}
|
||||
state = state.copyWith();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleCamera() async {
|
||||
final target = !state.isCameraEnabled;
|
||||
state = state.copyWith(isCameraEnabled: target);
|
||||
await _webrtcManager?.toggleCamera(target);
|
||||
|
||||
// Update local participant's video state
|
||||
if (_participants.isNotEmpty) {
|
||||
_participants[0].remoteParticipant.isVideoEnabled = target;
|
||||
state = state.copyWith(); // Trigger UI update
|
||||
if (_localParticipant != null) {
|
||||
final target = !_localParticipant!.isCameraEnabled();
|
||||
state = state.copyWith(isCameraEnabled: target);
|
||||
await _localParticipant!.setCameraEnabled(target);
|
||||
state = state.copyWith();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleScreenShare(BuildContext context) async {
|
||||
if (_webrtcManager == null) return;
|
||||
if (_localParticipant != null) {
|
||||
final target = !_localParticipant!.isScreenShareEnabled();
|
||||
state = state.copyWith(isScreenSharing: target);
|
||||
|
||||
try {
|
||||
if (state.isScreenSharing) {
|
||||
// Stop screen sharing - switch back to camera
|
||||
await _webrtcManager!.toggleCamera(state.isCameraEnabled);
|
||||
state = state.copyWith(isScreenSharing: false);
|
||||
} else {
|
||||
// Start screen sharing
|
||||
if (WebRTC.platformIsDesktop) {
|
||||
// For desktop, we need to get screen capture source
|
||||
// This would require implementing a screen selection dialog
|
||||
// For now, just toggle the state
|
||||
state = state.copyWith(isScreenSharing: true);
|
||||
} else if (WebRTC.platformIsWeb) {
|
||||
// For web, get display media directly
|
||||
await navigator.mediaDevices.getDisplayMedia({
|
||||
'video': true,
|
||||
'audio':
|
||||
false, // Screen sharing typically doesn't include system audio
|
||||
});
|
||||
|
||||
// Replace video track with screen sharing track
|
||||
// This is a simplified implementation
|
||||
state = state.copyWith(isScreenSharing: true);
|
||||
if (target && lk.lkPlatformIsDesktop()) {
|
||||
try {
|
||||
final source = await showDialog<DesktopCapturerSource>(
|
||||
context: context,
|
||||
builder: (context) => lk.ScreenSelectDialog(),
|
||||
);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
var track = await lk.LocalVideoTrack.createScreenShareTrack(
|
||||
lk.ScreenShareCaptureOptions(
|
||||
sourceId: source.id,
|
||||
maxFrameRate: 30.0,
|
||||
captureScreenAudio: true,
|
||||
),
|
||||
);
|
||||
await _localParticipant!.publishVideoTrack(track);
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
await _localParticipant!.setScreenShareEnabled(target);
|
||||
}
|
||||
} catch (e) {
|
||||
talker.error('[Call] Screen sharing error: $e');
|
||||
state = state.copyWith(error: 'Failed to toggle screen sharing: $e');
|
||||
|
||||
state = state.copyWith();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleSpeakerphone() async {
|
||||
if (!kIsWeb && (Platform.isIOS || Platform.isAndroid)) {
|
||||
try {
|
||||
// For mobile platforms, we can control audio routing
|
||||
// This is a simplified implementation
|
||||
final newSpeakerphoneState = !state.isSpeakerphone;
|
||||
state = state.copyWith(isSpeakerphone: newSpeakerphoneState);
|
||||
|
||||
// Note: Actual speakerphone control would require platform-specific code
|
||||
// For a full implementation, you'd need to use platform channels
|
||||
// to control audio routing on iOS/Android
|
||||
talker.info('[Call] Speakerphone toggled to: $newSpeakerphoneState');
|
||||
} catch (e) {
|
||||
talker.error('[Call] Speakerphone control error: $e');
|
||||
state = state.copyWith(error: 'Failed to toggle speakerphone: $e');
|
||||
}
|
||||
} else {
|
||||
// For web/desktop, speakerphone control is handled by the browser/OS
|
||||
state = state.copyWith(isSpeakerphone: !state.isSpeakerphone);
|
||||
}
|
||||
state = state.copyWith(isSpeakerphone: !state.isSpeakerphone);
|
||||
await lk.Hardware.instance.setSpeakerphoneOn(state.isSpeakerphone);
|
||||
state = state.copyWith();
|
||||
}
|
||||
|
||||
Future<void> disconnect() async {
|
||||
_webrtcManager?.dispose();
|
||||
_webrtcManager = null;
|
||||
_participantJoinedSubscription?.cancel();
|
||||
_participantLeftSubscription?.cancel();
|
||||
_participants.clear();
|
||||
state = state.copyWith(
|
||||
isConnected: false,
|
||||
isMicrophoneEnabled: false,
|
||||
isCameraEnabled: false,
|
||||
isScreenSharing: false,
|
||||
);
|
||||
// Disable wakelock when call disconnects
|
||||
WakelockPlus.disable();
|
||||
if (_room != null) {
|
||||
await _room!.disconnect();
|
||||
state = state.copyWith(
|
||||
isConnected: false,
|
||||
isMicrophoneEnabled: false,
|
||||
isCameraEnabled: false,
|
||||
isScreenSharing: false,
|
||||
);
|
||||
// Disable wakelock when call disconnects
|
||||
WakelockPlus.disable();
|
||||
}
|
||||
}
|
||||
|
||||
void setParticipantVolume(CallParticipantLive live, double volume) {
|
||||
// Store volume setting for this participant
|
||||
// Note: WebRTC doesn't have built-in per-participant volume control
|
||||
// This is just storing the preference for UI purposes
|
||||
// Actual volume control would need to be implemented at the audio rendering level
|
||||
participantsVolumes[live.remoteParticipant.id] = volume.clamp(0.0, 1.0);
|
||||
talker.info(
|
||||
'[Call] Volume set to $volume for participant ${live.remoteParticipant.id}',
|
||||
if (participantsVolumes[live.remoteParticipant.sid] == null) {
|
||||
participantsVolumes[live.remoteParticipant.sid] = 1;
|
||||
}
|
||||
Helper.setVolume(
|
||||
volume,
|
||||
live
|
||||
.remoteParticipant
|
||||
.audioTrackPublications
|
||||
.first
|
||||
.track!
|
||||
.mediaStreamTrack,
|
||||
);
|
||||
participantsVolumes[live.remoteParticipant.sid] = volume;
|
||||
}
|
||||
|
||||
double getParticipantVolume(CallParticipantLive live) {
|
||||
return participantsVolumes[live.remoteParticipant.id] ?? 1.0;
|
||||
return participantsVolumes[live.remoteParticipant.sid] ?? 1;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
@@ -423,10 +418,9 @@ class CallNotifier extends _$CallNotifier {
|
||||
isCameraEnabled: false,
|
||||
isScreenSharing: false,
|
||||
);
|
||||
_participantJoinedSubscription?.cancel();
|
||||
_participantLeftSubscription?.cancel();
|
||||
_webrtcManager?.dispose();
|
||||
_webrtcManager = null;
|
||||
_roomListener?.dispose();
|
||||
_room?.removeListener(_onRoomChange);
|
||||
_room?.dispose();
|
||||
_durationTimer?.cancel();
|
||||
_roomId = null;
|
||||
participantsVolumes = {};
|
||||
|
||||
@@ -295,7 +295,7 @@ as String?,
|
||||
/// @nodoc
|
||||
mixin _$CallParticipantLive implements DiagnosticableTreeMixin {
|
||||
|
||||
CallParticipant get participant; WebRTCParticipant get remoteParticipant;
|
||||
CallParticipant get participant; lk.Participant get remoteParticipant;
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -332,7 +332,7 @@ abstract mixin class $CallParticipantLiveCopyWith<$Res> {
|
||||
factory $CallParticipantLiveCopyWith(CallParticipantLive value, $Res Function(CallParticipantLive) _then) = _$CallParticipantLiveCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
CallParticipant participant, WebRTCParticipant remoteParticipant
|
||||
CallParticipant participant, lk.Participant remoteParticipant
|
||||
});
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ class _$CallParticipantLiveCopyWithImpl<$Res>
|
||||
return _then(_self.copyWith(
|
||||
participant: null == participant ? _self.participant : participant // ignore: cast_nullable_to_non_nullable
|
||||
as CallParticipant,remoteParticipant: null == remoteParticipant ? _self.remoteParticipant : remoteParticipant // ignore: cast_nullable_to_non_nullable
|
||||
as WebRTCParticipant,
|
||||
as lk.Participant,
|
||||
));
|
||||
}
|
||||
/// Create a copy of CallParticipantLive
|
||||
@@ -444,7 +444,7 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( CallParticipant participant, WebRTCParticipant remoteParticipant)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( CallParticipant participant, lk.Participant remoteParticipant)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallParticipantLive() when $default != null:
|
||||
return $default(_that.participant,_that.remoteParticipant);case _:
|
||||
@@ -465,7 +465,7 @@ return $default(_that.participant,_that.remoteParticipant);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( CallParticipant participant, WebRTCParticipant remoteParticipant) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( CallParticipant participant, lk.Participant remoteParticipant) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallParticipantLive():
|
||||
return $default(_that.participant,_that.remoteParticipant);}
|
||||
@@ -482,7 +482,7 @@ return $default(_that.participant,_that.remoteParticipant);}
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( CallParticipant participant, WebRTCParticipant remoteParticipant)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( CallParticipant participant, lk.Participant remoteParticipant)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CallParticipantLive() when $default != null:
|
||||
return $default(_that.participant,_that.remoteParticipant);case _:
|
||||
@@ -501,7 +501,7 @@ class _CallParticipantLive extends CallParticipantLive with DiagnosticableTreeMi
|
||||
|
||||
|
||||
@override final CallParticipant participant;
|
||||
@override final WebRTCParticipant remoteParticipant;
|
||||
@override final lk.Participant remoteParticipant;
|
||||
|
||||
/// Create a copy of CallParticipantLive
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -539,7 +539,7 @@ abstract mixin class _$CallParticipantLiveCopyWith<$Res> implements $CallPartici
|
||||
factory _$CallParticipantLiveCopyWith(_CallParticipantLive value, $Res Function(_CallParticipantLive) _then) = __$CallParticipantLiveCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
CallParticipant participant, WebRTCParticipant remoteParticipant
|
||||
CallParticipant participant, lk.Participant remoteParticipant
|
||||
});
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ class __$CallParticipantLiveCopyWithImpl<$Res>
|
||||
return _then(_CallParticipantLive(
|
||||
participant: null == participant ? _self.participant : participant // ignore: cast_nullable_to_non_nullable
|
||||
as CallParticipant,remoteParticipant: null == remoteParticipant ? _self.remoteParticipant : remoteParticipant // ignore: cast_nullable_to_non_nullable
|
||||
as WebRTCParticipant,
|
||||
as lk.Participant,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'call.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$callNotifierHash() => r'4015d326388553c46859fe537e84d2c9da4236c9';
|
||||
String _$callNotifierHash() => r'a8ca3f625c0db3ad9992033ae70864ce15efc281';
|
||||
|
||||
/// See also [CallNotifier].
|
||||
@ProviderFor(CallNotifier)
|
||||
|
||||
@@ -1,476 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/pods/chat/webrtc_signaling.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/talker.dart';
|
||||
|
||||
class WebRTCParticipant {
|
||||
final String id;
|
||||
final String name;
|
||||
final SnAccount userinfo;
|
||||
RTCPeerConnection? peerConnection;
|
||||
MediaStream? remoteStream;
|
||||
List<RTCIceCandidate> remoteCandidates = [];
|
||||
bool isAudioEnabled = true;
|
||||
bool isVideoEnabled = false;
|
||||
bool isConnected = false;
|
||||
bool isLocal = false;
|
||||
double audioLevel = 0.0;
|
||||
|
||||
WebRTCParticipant({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.userinfo,
|
||||
this.isAudioEnabled = true,
|
||||
this.isVideoEnabled = false,
|
||||
this.isLocal = false,
|
||||
});
|
||||
}
|
||||
|
||||
class WebRTCManager {
|
||||
final String roomId;
|
||||
final String serverUrl;
|
||||
late WebRTCSignaling _signaling;
|
||||
final Map<String, WebRTCParticipant> _participants = {};
|
||||
final Map<String, RTCPeerConnection> _peerConnections = {};
|
||||
|
||||
MediaStream? _localStream;
|
||||
Timer? _audioLevelTimer;
|
||||
|
||||
MediaStream? get localStream => _localStream;
|
||||
final StreamController<WebRTCParticipant> _participantController =
|
||||
StreamController<WebRTCParticipant>.broadcast();
|
||||
final StreamController<String> _participantLeftController =
|
||||
StreamController<String>.broadcast();
|
||||
|
||||
Stream<WebRTCParticipant> get onParticipantJoined =>
|
||||
_participantController.stream;
|
||||
Stream<String> get onParticipantLeft => _participantLeftController.stream;
|
||||
|
||||
WebRTCManager({required this.roomId, required this.serverUrl}) {
|
||||
_signaling = WebRTCSignaling(roomId: roomId);
|
||||
}
|
||||
|
||||
Future<void> initialize(Ref ref) async {
|
||||
final user = ref.watch(userInfoProvider).value!;
|
||||
_signaling.userId = user.id;
|
||||
_signaling.userName = user.name;
|
||||
_signaling.user = user;
|
||||
await _initializeLocalStream();
|
||||
_setupSignalingListeners();
|
||||
await _signaling.connect(ref);
|
||||
_startAudioLevelMonitoring();
|
||||
}
|
||||
|
||||
Future<void> _initializeLocalStream() async {
|
||||
try {
|
||||
_localStream = await navigator.mediaDevices.getUserMedia({
|
||||
'audio': true,
|
||||
'video': true,
|
||||
});
|
||||
talker.info('[WebRTC] Local stream initialized');
|
||||
} catch (e) {
|
||||
talker.error('[WebRTC] Failed to initialize local stream: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void _setupSignalingListeners() {
|
||||
_signaling.messages.listen((message) async {
|
||||
switch (message.type) {
|
||||
case 'offer':
|
||||
await _handleOffer(message.accountId, message.account, message.data);
|
||||
break;
|
||||
case 'answer':
|
||||
await _handleAnswer(message.accountId, message.data);
|
||||
break;
|
||||
case 'ice-candidate':
|
||||
await _handleIceCandidate(message.accountId, message.data);
|
||||
break;
|
||||
// CHANGED: Listen for new users joining the room.
|
||||
case 'user-joined':
|
||||
await _handleUserJoined(message.accountId, message.account);
|
||||
break;
|
||||
default:
|
||||
talker.warning(
|
||||
'[WebRTC Manager] Receieved an unknown type singaling message: ${message.type} with ${message.data}',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// CHANGED: The welcome message now drives connection initiation.
|
||||
_signaling.welcomeMessages.listen((welcome) {
|
||||
talker.info('[WebRTC Manager] Connected to room: ${welcome.roomId}');
|
||||
final existingParticipants =
|
||||
welcome.participants; // Assuming the server sends this.
|
||||
talker.info(
|
||||
'[WebRTC Manager] Existing participants: $existingParticipants',
|
||||
);
|
||||
|
||||
// The newcomer is responsible for initiating the connection to everyone else.
|
||||
for (final participant in existingParticipants) {
|
||||
if (participant.identity != _signaling.userId) {
|
||||
if (!_participants.containsKey(participant.identity)) {
|
||||
final webrtcParticipant = WebRTCParticipant(
|
||||
id: participant.identity,
|
||||
name: participant.name,
|
||||
userinfo: participant.account!,
|
||||
);
|
||||
_participants[participant.identity] = webrtcParticipant;
|
||||
_participantController.add(webrtcParticipant);
|
||||
}
|
||||
_createPeerConnection(participant.identity, isInitiator: true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// CHANGED: New handler for when an existing user is notified of a new peer.
|
||||
Future<void> _handleUserJoined(
|
||||
String participantId,
|
||||
SnAccount account,
|
||||
) async {
|
||||
talker.info(
|
||||
'[WebRTC Manager] User joined: $participantId. Waiting for their offer.',
|
||||
);
|
||||
// We don't need to be the initiator here. The newcomer will send us an offer.
|
||||
// We just create the peer connection to be ready for it.
|
||||
if (!_peerConnections.containsKey(participantId)) {
|
||||
// Create a participant object to represent the new user
|
||||
if (!_participants.containsKey(participantId)) {
|
||||
final participant = WebRTCParticipant(
|
||||
id: participantId,
|
||||
name: participantId,
|
||||
userinfo: account,
|
||||
); // Placeholder name
|
||||
_participants[participantId] = participant;
|
||||
_participantController.add(participant);
|
||||
}
|
||||
await _createPeerConnection(participantId, isInitiator: false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _createPeerConnection(
|
||||
String participantId, {
|
||||
bool isInitiator = false,
|
||||
}) async {
|
||||
talker.info(
|
||||
'[WebRTC] Creating peer connection to $participantId (initiator: $isInitiator)',
|
||||
);
|
||||
final configuration = {
|
||||
'iceServers': [
|
||||
{'urls': 'stun:stun.l.google.com:19302'},
|
||||
],
|
||||
};
|
||||
|
||||
final peerConnection = await createPeerConnection(configuration);
|
||||
_peerConnections[participantId] = peerConnection;
|
||||
_participants[participantId]!.peerConnection = peerConnection;
|
||||
|
||||
if (_localStream != null) {
|
||||
for (final track in _localStream!.getTracks()) {
|
||||
await peerConnection.addTrack(track, _localStream!);
|
||||
}
|
||||
}
|
||||
|
||||
peerConnection.onTrack = (event) {
|
||||
if (event.streams.isNotEmpty) {
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
participant.remoteStream = event.streams[0];
|
||||
participant.isConnected = true;
|
||||
|
||||
// Detect video tracks and update video enabled state
|
||||
final videoTracks = event.streams[0].getVideoTracks();
|
||||
if (videoTracks.isNotEmpty) {
|
||||
participant.isVideoEnabled = true;
|
||||
}
|
||||
|
||||
_participantController.add(participant);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
peerConnection.onIceCandidate = (candidate) {
|
||||
// CHANGED: Send candidate to the specific participant
|
||||
_signaling.sendIceCandidate(participantId, candidate);
|
||||
};
|
||||
|
||||
peerConnection.onConnectionState = (state) {
|
||||
talker.info('[WebRTC] Connection state for $participantId: $state');
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
participant.isConnected =
|
||||
state == RTCPeerConnectionState.RTCPeerConnectionStateConnected;
|
||||
_participantController.add(participant);
|
||||
}
|
||||
};
|
||||
|
||||
if (isInitiator) {
|
||||
final offer = await peerConnection.createOffer();
|
||||
await peerConnection.setLocalDescription(offer);
|
||||
// CHANGED: Send offer to the specific participant
|
||||
_signaling.sendOffer(participantId, offer);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleOffer(
|
||||
String from,
|
||||
SnAccount account,
|
||||
Map<String, dynamic> data,
|
||||
) async {
|
||||
final participantId = from;
|
||||
talker.info('[WebRTC Manager] Handling offer from $participantId');
|
||||
final offer = RTCSessionDescription(data['sdp'], data['type']);
|
||||
|
||||
if (!_peerConnections.containsKey(participantId)) {
|
||||
if (!_participants.containsKey(participantId)) {
|
||||
final participant = WebRTCParticipant(
|
||||
id: participantId,
|
||||
name: participantId,
|
||||
userinfo: account,
|
||||
);
|
||||
_participants[participantId] = participant;
|
||||
_participantController.add(participant);
|
||||
}
|
||||
await _createPeerConnection(participantId, isInitiator: false);
|
||||
}
|
||||
|
||||
final peerConnection = _peerConnections[participantId]!;
|
||||
await peerConnection.setRemoteDescription(offer);
|
||||
|
||||
final answer = await peerConnection.createAnswer();
|
||||
await peerConnection.setLocalDescription(answer);
|
||||
// CHANGED: Send answer to the specific participant
|
||||
_signaling.sendAnswer(participantId, answer);
|
||||
|
||||
// Process any queued ICE candidates
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
for (final candidate in participant.remoteCandidates) {
|
||||
await peerConnection.addCandidate(candidate);
|
||||
}
|
||||
participant.remoteCandidates.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleAnswer(String from, Map<String, dynamic> data) async {
|
||||
final participantId = from;
|
||||
talker.info('[WebRTC Manager] Handling answer from $participantId');
|
||||
final answer = RTCSessionDescription(data['sdp'], data['type']);
|
||||
|
||||
final peerConnection = _peerConnections[participantId];
|
||||
if (peerConnection != null) {
|
||||
await peerConnection.setRemoteDescription(answer);
|
||||
|
||||
// Process any queued ICE candidates
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
for (final candidate in participant.remoteCandidates) {
|
||||
await peerConnection.addCandidate(candidate);
|
||||
}
|
||||
participant.remoteCandidates.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleIceCandidate(
|
||||
String from,
|
||||
Map<String, dynamic> data,
|
||||
) async {
|
||||
final participantId = from;
|
||||
final candidate = RTCIceCandidate(
|
||||
data['candidate'],
|
||||
data['sdpMid'],
|
||||
data['sdpMLineIndex'],
|
||||
);
|
||||
|
||||
final participant = _participants[participantId];
|
||||
if (participant != null) {
|
||||
final pc = participant.peerConnection;
|
||||
if (pc != null) {
|
||||
await pc.addCandidate(candidate);
|
||||
} else {
|
||||
participant.remoteCandidates.add(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> replaceMediaStream(Map<String, dynamic> constraints) async {
|
||||
try {
|
||||
final newStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
final newVideoTrack = newStream.getVideoTracks().firstOrNull;
|
||||
final newAudioTrack = newStream.getAudioTracks().firstOrNull;
|
||||
|
||||
if (_localStream != null) {
|
||||
final oldVideoTrack = _localStream!.getVideoTracks().firstOrNull;
|
||||
final oldAudioTrack = _localStream!.getAudioTracks().firstOrNull;
|
||||
|
||||
// Replace tracks in all existing peer connections
|
||||
for (final pc in _peerConnections.values) {
|
||||
final senders = await pc.getSenders();
|
||||
for (final sender in senders) {
|
||||
if (newVideoTrack != null && sender.track == oldVideoTrack) {
|
||||
await sender.replaceTrack(newVideoTrack);
|
||||
} else if (newAudioTrack != null && sender.track == oldAudioTrack) {
|
||||
await sender.replaceTrack(newAudioTrack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop old tracks and update local stream
|
||||
for (final track in _localStream!.getTracks()) {
|
||||
track.stop();
|
||||
}
|
||||
}
|
||||
|
||||
_localStream = newStream;
|
||||
talker.info('[WebRTC] Media stream replaced with new constraints');
|
||||
} catch (e) {
|
||||
talker.error('[WebRTC] Failed to replace media stream: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleMicrophone(bool enabled) async {
|
||||
if (_localStream != null) {
|
||||
final audioTracks = _localStream!.getAudioTracks();
|
||||
for (final track in audioTracks) {
|
||||
track.enabled = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleCamera(bool enabled) async {
|
||||
if (_localStream != null) {
|
||||
_localStream!.getVideoTracks().forEach((track) {
|
||||
track.enabled = enabled;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> switchCamera(String deviceId) async {
|
||||
await replaceMediaStream({
|
||||
'audio': _localStream?.getAudioTracks().isNotEmpty ?? true,
|
||||
'video': {'deviceId': deviceId},
|
||||
});
|
||||
talker.info('[WebRTC] Switched to camera device: $deviceId');
|
||||
}
|
||||
|
||||
Future<void> switchMicrophone(String deviceId) async {
|
||||
await replaceMediaStream({
|
||||
'audio': {'deviceId': deviceId},
|
||||
'video': _localStream?.getVideoTracks().isNotEmpty ?? true,
|
||||
});
|
||||
talker.info('[WebRTC] Switched to microphone device: $deviceId');
|
||||
}
|
||||
|
||||
Future<List<MediaDeviceInfo>> getVideoDevices() async {
|
||||
try {
|
||||
final devices = await navigator.mediaDevices.enumerateDevices();
|
||||
return devices.where((device) => device.kind == 'videoinput').toList();
|
||||
} catch (e) {
|
||||
talker.error('[WebRTC] Failed to enumerate video devices: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<MediaDeviceInfo>> getAudioDevices() async {
|
||||
try {
|
||||
final devices = await navigator.mediaDevices.enumerateDevices();
|
||||
return devices.where((device) => device.kind == 'audioinput').toList();
|
||||
} catch (e) {
|
||||
talker.error('[WebRTC] Failed to enumerate audio devices: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
void _startAudioLevelMonitoring() {
|
||||
_audioLevelTimer?.cancel();
|
||||
_audioLevelTimer = Timer.periodic(const Duration(milliseconds: 100), (_) {
|
||||
_updateAudioLevels();
|
||||
});
|
||||
}
|
||||
|
||||
void _stopAudioLevelMonitoring() {
|
||||
_audioLevelTimer?.cancel();
|
||||
_audioLevelTimer = null;
|
||||
}
|
||||
|
||||
Future<void> _updateAudioLevels() async {
|
||||
bool hasUpdates = false;
|
||||
|
||||
for (final participant in _participants.values) {
|
||||
if (participant.remoteStream != null && participant.isAudioEnabled) {
|
||||
final audioTracks = participant.remoteStream!.getAudioTracks();
|
||||
if (audioTracks.isNotEmpty) {
|
||||
try {
|
||||
// Try to get stats for more accurate audio level detection
|
||||
final pc = participant.peerConnection;
|
||||
if (pc != null) {
|
||||
final stats = await pc.getStats();
|
||||
double maxAudioLevel = 0.0;
|
||||
|
||||
// Look for audio receiver stats
|
||||
for (var report in stats) {
|
||||
if (report.type == 'inbound-rtp' &&
|
||||
report.values['mediaType'] == 'audio') {
|
||||
final audioLevel = report.values['audioLevel'] as double?;
|
||||
if (audioLevel != null && audioLevel > maxAudioLevel) {
|
||||
maxAudioLevel = audioLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we got stats, use them; otherwise use a simple heuristic
|
||||
if (maxAudioLevel > 0) {
|
||||
participant.audioLevel = maxAudioLevel.clamp(0.0, 1.0);
|
||||
} else {
|
||||
// Simple heuristic: if audio track is enabled, assume some level
|
||||
// In a real app, you'd analyze the actual audio data
|
||||
participant.audioLevel = audioTracks[0].enabled ? 0.5 : 0.0;
|
||||
}
|
||||
} else {
|
||||
// Fallback for local participant or when no PC available
|
||||
participant.audioLevel = participant.isLocal ? 0.0 : 0.3;
|
||||
}
|
||||
|
||||
hasUpdates = true;
|
||||
} catch (e) {
|
||||
talker.warning('[WebRTC] Failed to update audio level for ${participant.id}: $e');
|
||||
participant.audioLevel = 0.0;
|
||||
}
|
||||
} else {
|
||||
participant.audioLevel = 0.0;
|
||||
}
|
||||
} else {
|
||||
participant.audioLevel = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners if there were updates (throttled to avoid excessive updates)
|
||||
if (hasUpdates) {
|
||||
// This will trigger UI updates for speaking indicators
|
||||
}
|
||||
}
|
||||
|
||||
List<WebRTCParticipant> get participants => _participants.values.toList();
|
||||
|
||||
void dispose() {
|
||||
_stopAudioLevelMonitoring();
|
||||
_signaling.disconnect();
|
||||
for (final pc in _peerConnections.values) {
|
||||
pc.close();
|
||||
}
|
||||
_peerConnections.clear();
|
||||
for (var p in _participants.values) {
|
||||
p.remoteCandidates.clear();
|
||||
}
|
||||
_participants.clear();
|
||||
_localStream?.dispose();
|
||||
_participantController.close();
|
||||
_participantLeftController.close();
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_webrtc/flutter_webrtc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/models/chat.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/websocket.dart';
|
||||
import 'package:web_socket_channel/io.dart';
|
||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||
import 'package:island/talker.dart';
|
||||
|
||||
part 'webrtc_signaling.freezed.dart';
|
||||
part 'webrtc_signaling.g.dart';
|
||||
|
||||
@freezed
|
||||
sealed class SignalingMessage with _$SignalingMessage {
|
||||
const factory SignalingMessage({
|
||||
required String type,
|
||||
// CHANGED: Added 'to' field for directed messaging
|
||||
String? to,
|
||||
required String accountId,
|
||||
required SnAccount account,
|
||||
required Map<String, dynamic> data,
|
||||
}) = _SignalingMessage;
|
||||
|
||||
factory SignalingMessage.fromJson(Map<String, dynamic> json) =>
|
||||
_$SignalingMessageFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class WebRTCWelcomeMessage with _$WebRTCWelcomeMessage {
|
||||
const factory WebRTCWelcomeMessage({
|
||||
required String userId,
|
||||
required String roomId,
|
||||
required String message,
|
||||
required String timestamp,
|
||||
// CHANGED: Added participants list
|
||||
@Default([]) List<CallParticipant> participants,
|
||||
}) = _WebRTCWelcomeMessage;
|
||||
|
||||
factory WebRTCWelcomeMessage.fromJson(Map<String, dynamic> json) =>
|
||||
_$WebRTCWelcomeMessageFromJson(json);
|
||||
}
|
||||
|
||||
class WebRTCSignaling {
|
||||
final String roomId;
|
||||
late final String userId;
|
||||
late final String userName;
|
||||
late SnAccount user;
|
||||
final StreamController<SignalingMessage> _messageController =
|
||||
StreamController<SignalingMessage>.broadcast();
|
||||
final StreamController<WebRTCWelcomeMessage> _welcomeController =
|
||||
StreamController<WebRTCWelcomeMessage>.broadcast();
|
||||
WebSocketChannel? _channel;
|
||||
Timer? _heartbeatTimer;
|
||||
|
||||
Stream<SignalingMessage> get messages => _messageController.stream;
|
||||
Stream<WebRTCWelcomeMessage> get welcomeMessages => _welcomeController.stream;
|
||||
|
||||
WebRTCSignaling({required this.roomId});
|
||||
|
||||
Future<void> connect(Ref ref) async {
|
||||
final baseUrl = ref.watch(serverUrlProvider);
|
||||
final token = await getToken(ref.watch(tokenProvider));
|
||||
|
||||
final url = '$baseUrl/sphere/chat/realtime/$roomId'.replaceFirst(
|
||||
'http',
|
||||
'ws',
|
||||
);
|
||||
|
||||
talker.info('[WebRTC Signaling] Trying connecting to $url');
|
||||
try {
|
||||
if (kIsWeb) {
|
||||
_channel = WebSocketChannel.connect(Uri.parse('$url?tk=$token'));
|
||||
} else {
|
||||
_channel = IOWebSocketChannel.connect(
|
||||
Uri.parse(url),
|
||||
headers: {'Authorization': 'AtField $token'},
|
||||
);
|
||||
}
|
||||
await _channel!.ready;
|
||||
|
||||
// Start heartbeat timer
|
||||
_heartbeatTimer = Timer.periodic(const Duration(seconds: 30), (timer) => _sendHeartbeat());
|
||||
|
||||
_channel!.stream.listen(
|
||||
(data) {
|
||||
final dataStr =
|
||||
data is Uint8List ? utf8.decode(data) : data.toString();
|
||||
final packet = WebSocketPacket.fromJson(jsonDecode(dataStr));
|
||||
talker.info(
|
||||
'[WebRTC Signaling] Recieved a singal message with packet type: ${packet.type}',
|
||||
);
|
||||
if (packet.type == 'webrtc') {
|
||||
try {
|
||||
final welcomeMessage = WebRTCWelcomeMessage.fromJson(
|
||||
packet.data!,
|
||||
);
|
||||
_welcomeController.add(welcomeMessage);
|
||||
talker.info(
|
||||
'[WebRTC Signaling] Welcome message received: ${welcomeMessage.message}',
|
||||
);
|
||||
} catch (e) {
|
||||
talker.error(
|
||||
'[WebRTC Signaling] Failed to parse welcome message: $e',
|
||||
);
|
||||
}
|
||||
} else if (packet.type == 'webrtc.signal') {
|
||||
try {
|
||||
final signalingMessage = SignalingMessage.fromJson(packet.data!);
|
||||
// CHANGED: Ensure we only process messages intended for us if the 'to' field is present
|
||||
if (signalingMessage.to == null ||
|
||||
signalingMessage.to == userId) {
|
||||
_messageController.add(signalingMessage);
|
||||
}
|
||||
} catch (e) {
|
||||
talker.error(
|
||||
'[WebRTC Signaling] Failed to parse signaling message: $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: (error) {
|
||||
talker.error('[WebRTC Signaling] WebSocket error: $error');
|
||||
_messageController.addError(error);
|
||||
_welcomeController.addError(error);
|
||||
},
|
||||
onDone: () {
|
||||
talker.info('[WebRTC Signaling] WebSocket connection closed');
|
||||
_messageController.close();
|
||||
_welcomeController.close();
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
talker.error('[WebRTC Signaling] Failed to connect: $err');
|
||||
_messageController.addError(err);
|
||||
_welcomeController.addError(err);
|
||||
}
|
||||
}
|
||||
|
||||
void sendMessage(SignalingMessage message) {
|
||||
if (_channel == null) return;
|
||||
talker.info(
|
||||
'[WebRTC Signaling] Sending a message with message type: ${message.type} to ${message.to}',
|
||||
);
|
||||
final packet = WebSocketPacket(
|
||||
type: 'webrtc.signal',
|
||||
data: message.toJson(),
|
||||
);
|
||||
_channel!.sink.add(jsonEncode(packet.toJson()));
|
||||
}
|
||||
|
||||
// CHANGED: All send methods now correctly use the `to` parameter
|
||||
void sendOffer(String to, RTCSessionDescription offer) {
|
||||
sendMessage(
|
||||
SignalingMessage(
|
||||
type: 'offer',
|
||||
to: to,
|
||||
accountId: userId,
|
||||
account: user,
|
||||
data: {'sdp': offer.sdp, 'type': offer.type},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void sendAnswer(String to, RTCSessionDescription answer) {
|
||||
sendMessage(
|
||||
SignalingMessage(
|
||||
type: 'answer',
|
||||
to: to,
|
||||
accountId: userId,
|
||||
account: user,
|
||||
data: {'sdp': answer.sdp, 'type': answer.type},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void sendIceCandidate(String to, RTCIceCandidate candidate) {
|
||||
sendMessage(
|
||||
SignalingMessage(
|
||||
type: 'ice-candidate',
|
||||
to: to,
|
||||
accountId: userId,
|
||||
account: user,
|
||||
data: {
|
||||
'candidate': candidate.candidate,
|
||||
'sdpMid': candidate.sdpMid,
|
||||
'sdpMLineIndex': candidate.sdpMLineIndex,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _sendHeartbeat() {
|
||||
if (_channel == null) return;
|
||||
talker.info('[WebRTC Signaling] Sending heartbeat');
|
||||
final packet = WebSocketPacket(type: 'heartbeat', data: null);
|
||||
_channel!.sink.add(jsonEncode(packet.toJson()));
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
_heartbeatTimer?.cancel();
|
||||
_channel?.sink.close();
|
||||
_messageController.close();
|
||||
_welcomeController.close();
|
||||
}
|
||||
}
|
||||
@@ -1,611 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'webrtc_signaling.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SignalingMessage implements DiagnosticableTreeMixin {
|
||||
|
||||
String get type;// CHANGED: Added 'to' field for directed messaging
|
||||
String? get to; String get accountId; SnAccount get account; Map<String, dynamic> get data;
|
||||
/// Create a copy of SignalingMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$SignalingMessageCopyWith<SignalingMessage> get copyWith => _$SignalingMessageCopyWithImpl<SignalingMessage>(this as SignalingMessage, _$identity);
|
||||
|
||||
/// Serializes this SignalingMessage to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'SignalingMessage'))
|
||||
..add(DiagnosticsProperty('type', type))..add(DiagnosticsProperty('to', to))..add(DiagnosticsProperty('accountId', accountId))..add(DiagnosticsProperty('account', account))..add(DiagnosticsProperty('data', data));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SignalingMessage&&(identical(other.type, type) || other.type == type)&&(identical(other.to, to) || other.to == to)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&const DeepCollectionEquality().equals(other.data, data));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,type,to,accountId,account,const DeepCollectionEquality().hash(data));
|
||||
|
||||
@override
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'SignalingMessage(type: $type, to: $to, accountId: $accountId, account: $account, data: $data)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $SignalingMessageCopyWith<$Res> {
|
||||
factory $SignalingMessageCopyWith(SignalingMessage value, $Res Function(SignalingMessage) _then) = _$SignalingMessageCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String type, String? to, String accountId, SnAccount account, Map<String, dynamic> data
|
||||
});
|
||||
|
||||
|
||||
$SnAccountCopyWith<$Res> get account;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$SignalingMessageCopyWithImpl<$Res>
|
||||
implements $SignalingMessageCopyWith<$Res> {
|
||||
_$SignalingMessageCopyWithImpl(this._self, this._then);
|
||||
|
||||
final SignalingMessage _self;
|
||||
final $Res Function(SignalingMessage) _then;
|
||||
|
||||
/// Create a copy of SignalingMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? to = freezed,Object? accountId = null,Object? account = null,Object? data = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as String,to: freezed == to ? _self.to : to // ignore: cast_nullable_to_non_nullable
|
||||
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String,account: null == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||
as SnAccount,data: null == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,
|
||||
));
|
||||
}
|
||||
/// Create a copy of SignalingMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnAccountCopyWith<$Res> get account {
|
||||
|
||||
return $SnAccountCopyWith<$Res>(_self.account, (value) {
|
||||
return _then(_self.copyWith(account: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [SignalingMessage].
|
||||
extension SignalingMessagePatterns on SignalingMessage {
|
||||
/// 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( _SignalingMessage value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SignalingMessage() 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( _SignalingMessage value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SignalingMessage():
|
||||
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( _SignalingMessage value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SignalingMessage() 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 type, String? to, String accountId, SnAccount account, Map<String, dynamic> data)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SignalingMessage() when $default != null:
|
||||
return $default(_that.type,_that.to,_that.accountId,_that.account,_that.data);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 type, String? to, String accountId, SnAccount account, Map<String, dynamic> data) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SignalingMessage():
|
||||
return $default(_that.type,_that.to,_that.accountId,_that.account,_that.data);}
|
||||
}
|
||||
/// 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 type, String? to, String accountId, SnAccount account, Map<String, dynamic> data)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SignalingMessage() when $default != null:
|
||||
return $default(_that.type,_that.to,_that.accountId,_that.account,_that.data);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _SignalingMessage with DiagnosticableTreeMixin implements SignalingMessage {
|
||||
const _SignalingMessage({required this.type, this.to, required this.accountId, required this.account, required final Map<String, dynamic> data}): _data = data;
|
||||
factory _SignalingMessage.fromJson(Map<String, dynamic> json) => _$SignalingMessageFromJson(json);
|
||||
|
||||
@override final String type;
|
||||
// CHANGED: Added 'to' field for directed messaging
|
||||
@override final String? to;
|
||||
@override final String accountId;
|
||||
@override final SnAccount account;
|
||||
final Map<String, dynamic> _data;
|
||||
@override Map<String, dynamic> get data {
|
||||
if (_data is EqualUnmodifiableMapView) return _data;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_data);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of SignalingMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$SignalingMessageCopyWith<_SignalingMessage> get copyWith => __$SignalingMessageCopyWithImpl<_SignalingMessage>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$SignalingMessageToJson(this, );
|
||||
}
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'SignalingMessage'))
|
||||
..add(DiagnosticsProperty('type', type))..add(DiagnosticsProperty('to', to))..add(DiagnosticsProperty('accountId', accountId))..add(DiagnosticsProperty('account', account))..add(DiagnosticsProperty('data', data));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SignalingMessage&&(identical(other.type, type) || other.type == type)&&(identical(other.to, to) || other.to == to)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&const DeepCollectionEquality().equals(other._data, _data));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,type,to,accountId,account,const DeepCollectionEquality().hash(_data));
|
||||
|
||||
@override
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'SignalingMessage(type: $type, to: $to, accountId: $accountId, account: $account, data: $data)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$SignalingMessageCopyWith<$Res> implements $SignalingMessageCopyWith<$Res> {
|
||||
factory _$SignalingMessageCopyWith(_SignalingMessage value, $Res Function(_SignalingMessage) _then) = __$SignalingMessageCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String type, String? to, String accountId, SnAccount account, Map<String, dynamic> data
|
||||
});
|
||||
|
||||
|
||||
@override $SnAccountCopyWith<$Res> get account;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$SignalingMessageCopyWithImpl<$Res>
|
||||
implements _$SignalingMessageCopyWith<$Res> {
|
||||
__$SignalingMessageCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _SignalingMessage _self;
|
||||
final $Res Function(_SignalingMessage) _then;
|
||||
|
||||
/// Create a copy of SignalingMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? to = freezed,Object? accountId = null,Object? account = null,Object? data = null,}) {
|
||||
return _then(_SignalingMessage(
|
||||
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as String,to: freezed == to ? _self.to : to // ignore: cast_nullable_to_non_nullable
|
||||
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||
as String,account: null == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
|
||||
as SnAccount,data: null == data ? _self._data : data // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of SignalingMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnAccountCopyWith<$Res> get account {
|
||||
|
||||
return $SnAccountCopyWith<$Res>(_self.account, (value) {
|
||||
return _then(_self.copyWith(account: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$WebRTCWelcomeMessage implements DiagnosticableTreeMixin {
|
||||
|
||||
String get userId; String get roomId; String get message; String get timestamp;// CHANGED: Added participants list
|
||||
List<CallParticipant> get participants;
|
||||
/// Create a copy of WebRTCWelcomeMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$WebRTCWelcomeMessageCopyWith<WebRTCWelcomeMessage> get copyWith => _$WebRTCWelcomeMessageCopyWithImpl<WebRTCWelcomeMessage>(this as WebRTCWelcomeMessage, _$identity);
|
||||
|
||||
/// Serializes this WebRTCWelcomeMessage to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'WebRTCWelcomeMessage'))
|
||||
..add(DiagnosticsProperty('userId', userId))..add(DiagnosticsProperty('roomId', roomId))..add(DiagnosticsProperty('message', message))..add(DiagnosticsProperty('timestamp', timestamp))..add(DiagnosticsProperty('participants', participants));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is WebRTCWelcomeMessage&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.roomId, roomId) || other.roomId == roomId)&&(identical(other.message, message) || other.message == message)&&(identical(other.timestamp, timestamp) || other.timestamp == timestamp)&&const DeepCollectionEquality().equals(other.participants, participants));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,userId,roomId,message,timestamp,const DeepCollectionEquality().hash(participants));
|
||||
|
||||
@override
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'WebRTCWelcomeMessage(userId: $userId, roomId: $roomId, message: $message, timestamp: $timestamp, participants: $participants)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $WebRTCWelcomeMessageCopyWith<$Res> {
|
||||
factory $WebRTCWelcomeMessageCopyWith(WebRTCWelcomeMessage value, $Res Function(WebRTCWelcomeMessage) _then) = _$WebRTCWelcomeMessageCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String userId, String roomId, String message, String timestamp, List<CallParticipant> participants
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$WebRTCWelcomeMessageCopyWithImpl<$Res>
|
||||
implements $WebRTCWelcomeMessageCopyWith<$Res> {
|
||||
_$WebRTCWelcomeMessageCopyWithImpl(this._self, this._then);
|
||||
|
||||
final WebRTCWelcomeMessage _self;
|
||||
final $Res Function(WebRTCWelcomeMessage) _then;
|
||||
|
||||
/// Create a copy of WebRTCWelcomeMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? userId = null,Object? roomId = null,Object? message = null,Object? timestamp = null,Object? participants = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
|
||||
as String,roomId: null == roomId ? _self.roomId : roomId // ignore: cast_nullable_to_non_nullable
|
||||
as String,message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable
|
||||
as String,timestamp: null == timestamp ? _self.timestamp : timestamp // ignore: cast_nullable_to_non_nullable
|
||||
as String,participants: null == participants ? _self.participants : participants // ignore: cast_nullable_to_non_nullable
|
||||
as List<CallParticipant>,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [WebRTCWelcomeMessage].
|
||||
extension WebRTCWelcomeMessagePatterns on WebRTCWelcomeMessage {
|
||||
/// 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( _WebRTCWelcomeMessage value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _WebRTCWelcomeMessage() 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( _WebRTCWelcomeMessage value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _WebRTCWelcomeMessage():
|
||||
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( _WebRTCWelcomeMessage value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _WebRTCWelcomeMessage() 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 userId, String roomId, String message, String timestamp, List<CallParticipant> participants)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _WebRTCWelcomeMessage() when $default != null:
|
||||
return $default(_that.userId,_that.roomId,_that.message,_that.timestamp,_that.participants);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 userId, String roomId, String message, String timestamp, List<CallParticipant> participants) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _WebRTCWelcomeMessage():
|
||||
return $default(_that.userId,_that.roomId,_that.message,_that.timestamp,_that.participants);}
|
||||
}
|
||||
/// 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 userId, String roomId, String message, String timestamp, List<CallParticipant> participants)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _WebRTCWelcomeMessage() when $default != null:
|
||||
return $default(_that.userId,_that.roomId,_that.message,_that.timestamp,_that.participants);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _WebRTCWelcomeMessage with DiagnosticableTreeMixin implements WebRTCWelcomeMessage {
|
||||
const _WebRTCWelcomeMessage({required this.userId, required this.roomId, required this.message, required this.timestamp, final List<CallParticipant> participants = const []}): _participants = participants;
|
||||
factory _WebRTCWelcomeMessage.fromJson(Map<String, dynamic> json) => _$WebRTCWelcomeMessageFromJson(json);
|
||||
|
||||
@override final String userId;
|
||||
@override final String roomId;
|
||||
@override final String message;
|
||||
@override final String timestamp;
|
||||
// CHANGED: Added participants list
|
||||
final List<CallParticipant> _participants;
|
||||
// CHANGED: Added participants list
|
||||
@override@JsonKey() List<CallParticipant> get participants {
|
||||
if (_participants is EqualUnmodifiableListView) return _participants;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_participants);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of WebRTCWelcomeMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$WebRTCWelcomeMessageCopyWith<_WebRTCWelcomeMessage> get copyWith => __$WebRTCWelcomeMessageCopyWithImpl<_WebRTCWelcomeMessage>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$WebRTCWelcomeMessageToJson(this, );
|
||||
}
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'WebRTCWelcomeMessage'))
|
||||
..add(DiagnosticsProperty('userId', userId))..add(DiagnosticsProperty('roomId', roomId))..add(DiagnosticsProperty('message', message))..add(DiagnosticsProperty('timestamp', timestamp))..add(DiagnosticsProperty('participants', participants));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _WebRTCWelcomeMessage&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.roomId, roomId) || other.roomId == roomId)&&(identical(other.message, message) || other.message == message)&&(identical(other.timestamp, timestamp) || other.timestamp == timestamp)&&const DeepCollectionEquality().equals(other._participants, _participants));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,userId,roomId,message,timestamp,const DeepCollectionEquality().hash(_participants));
|
||||
|
||||
@override
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'WebRTCWelcomeMessage(userId: $userId, roomId: $roomId, message: $message, timestamp: $timestamp, participants: $participants)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$WebRTCWelcomeMessageCopyWith<$Res> implements $WebRTCWelcomeMessageCopyWith<$Res> {
|
||||
factory _$WebRTCWelcomeMessageCopyWith(_WebRTCWelcomeMessage value, $Res Function(_WebRTCWelcomeMessage) _then) = __$WebRTCWelcomeMessageCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String userId, String roomId, String message, String timestamp, List<CallParticipant> participants
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$WebRTCWelcomeMessageCopyWithImpl<$Res>
|
||||
implements _$WebRTCWelcomeMessageCopyWith<$Res> {
|
||||
__$WebRTCWelcomeMessageCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _WebRTCWelcomeMessage _self;
|
||||
final $Res Function(_WebRTCWelcomeMessage) _then;
|
||||
|
||||
/// Create a copy of WebRTCWelcomeMessage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? userId = null,Object? roomId = null,Object? message = null,Object? timestamp = null,Object? participants = null,}) {
|
||||
return _then(_WebRTCWelcomeMessage(
|
||||
userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
|
||||
as String,roomId: null == roomId ? _self.roomId : roomId // ignore: cast_nullable_to_non_nullable
|
||||
as String,message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable
|
||||
as String,timestamp: null == timestamp ? _self.timestamp : timestamp // ignore: cast_nullable_to_non_nullable
|
||||
as String,participants: null == participants ? _self._participants : participants // ignore: cast_nullable_to_non_nullable
|
||||
as List<CallParticipant>,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -1,49 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'webrtc_signaling.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_SignalingMessage _$SignalingMessageFromJson(Map<String, dynamic> json) =>
|
||||
_SignalingMessage(
|
||||
type: json['type'] as String,
|
||||
to: json['to'] as String?,
|
||||
accountId: json['account_id'] as String,
|
||||
account: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||
data: json['data'] as Map<String, dynamic>,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SignalingMessageToJson(_SignalingMessage instance) =>
|
||||
<String, dynamic>{
|
||||
'type': instance.type,
|
||||
'to': instance.to,
|
||||
'account_id': instance.accountId,
|
||||
'account': instance.account.toJson(),
|
||||
'data': instance.data,
|
||||
};
|
||||
|
||||
_WebRTCWelcomeMessage _$WebRTCWelcomeMessageFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _WebRTCWelcomeMessage(
|
||||
userId: json['user_id'] as String,
|
||||
roomId: json['room_id'] as String,
|
||||
message: json['message'] as String,
|
||||
timestamp: json['timestamp'] as String,
|
||||
participants:
|
||||
(json['participants'] as List<dynamic>?)
|
||||
?.map((e) => CallParticipant.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
const [],
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$WebRTCWelcomeMessageToJson(
|
||||
_WebRTCWelcomeMessage instance,
|
||||
) => <String, dynamic>{
|
||||
'user_id': instance.userId,
|
||||
'room_id': instance.roomId,
|
||||
'message': instance.message,
|
||||
'timestamp': instance.timestamp,
|
||||
'participants': instance.participants.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Map<String, dynamic> _$ThemeColorsToJson(_ThemeColors instance) =>
|
||||
// **************************************************************************
|
||||
|
||||
String _$appSettingsNotifierHash() =>
|
||||
r'10ebd893c39d24ae588a4c0bf4144ee4656465a4';
|
||||
r'22b695f2023e3251db3296858acd701f7211d757';
|
||||
|
||||
/// See also [AppSettingsNotifier].
|
||||
@ProviderFor(AppSettingsNotifier)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'event_calendar.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$eventCalendarHash() => r'72232fc044ac3c99b855dca37ff2f06a64be0afb';
|
||||
String _$eventCalendarHash() => r'3a33581c28bcd44bc5eb3abdb770171b4d275a5d';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -100,16 +100,12 @@ class WebSocketService {
|
||||
}
|
||||
},
|
||||
onDone: () {
|
||||
talker.info(
|
||||
'[WebSocket] Connection closed, attempting to reconnect...',
|
||||
);
|
||||
talker.info('[WebSocket] Connection closed, attempting to reconnect...');
|
||||
_scheduleReconnect();
|
||||
_statusStreamController.sink.add(WebSocketState.disconnected());
|
||||
},
|
||||
onError: (error) {
|
||||
talker.error(
|
||||
'[WebSocket] Error occurred: $error, attempting to reconnect...',
|
||||
);
|
||||
talker.error('[WebSocket] Error occurred: $error, attempting to reconnect...');
|
||||
_scheduleReconnect();
|
||||
_statusStreamController.sink.add(
|
||||
WebSocketState.error(error.toString()),
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'leveling.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$levelingHistoryNotifierHash() =>
|
||||
r'e795f9b7911c9e50f15c095ea237cb0e87bf1e89';
|
||||
r'de51012e1590ac46388b6f3f2050b21cb96698d1';
|
||||
|
||||
/// See also [LevelingHistoryNotifier].
|
||||
@ProviderFor(LevelingHistoryNotifier)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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}',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart' hide ConnectionState;
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -9,6 +9,8 @@ import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/chat/call_button.dart';
|
||||
import 'package:island/widgets/chat/call_overlay.dart';
|
||||
import 'package:island/widgets/chat/call_participant_tile.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:livekit_client/livekit_client.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
@@ -24,13 +26,32 @@ class CallScreen extends HookConsumerWidget {
|
||||
|
||||
useEffect(() {
|
||||
talker.info('[Call] Joining the call...');
|
||||
Future(() {
|
||||
callNotifier.joinRoom(roomId);
|
||||
callNotifier.joinRoom(roomId).catchError((_) {
|
||||
showConfirmAlert(
|
||||
'Seems there already has a call connected, do you want override it?',
|
||||
'Call already connected',
|
||||
).then((value) {
|
||||
if (value != true) return;
|
||||
talker.info('[Call] Joining the call... with overrides');
|
||||
callNotifier.disconnect();
|
||||
callNotifier.dispose();
|
||||
callNotifier.joinRoom(roomId);
|
||||
});
|
||||
});
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
final allAudioOnly = callNotifier.participants.every((p) => !p.hasVideo);
|
||||
final allAudioOnly = callNotifier.participants.every(
|
||||
(p) =>
|
||||
!(p.hasVideo &&
|
||||
p.remoteParticipant.trackPublications.values.any(
|
||||
(pub) =>
|
||||
pub.track != null &&
|
||||
pub.kind == TrackType.VIDEO &&
|
||||
!pub.muted &&
|
||||
!pub.isDisposed,
|
||||
)),
|
||||
);
|
||||
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
@@ -46,7 +67,12 @@ class CallScreen extends HookConsumerWidget {
|
||||
Text(
|
||||
callState.isConnected
|
||||
? formatDuration(callState.duration)
|
||||
: 'connecting'.tr(),
|
||||
: (switch (callNotifier.room?.connectionState) {
|
||||
ConnectionState.connected => 'connected',
|
||||
ConnectionState.connecting => 'connecting',
|
||||
ConnectionState.reconnecting => 'reconnecting',
|
||||
_ => 'disconnected',
|
||||
}).tr(),
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
@@ -133,7 +159,19 @@ class CallScreen extends HookConsumerWidget {
|
||||
|
||||
// Stage view: show main speaker(s) large, others in row
|
||||
final mainSpeakers =
|
||||
participants.where((p) => p.hasVideo).toList();
|
||||
participants
|
||||
.where(
|
||||
(p) => p
|
||||
.remoteParticipant
|
||||
.trackPublications
|
||||
.values
|
||||
.any(
|
||||
(pub) =>
|
||||
pub.track != null &&
|
||||
pub.kind == TrackType.VIDEO,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
if (mainSpeakers.isEmpty && participants.isNotEmpty) {
|
||||
mainSpeakers.add(participants.first);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,121 @@ 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: const EdgeInsets.only(left: 8, right: 8, top: 4),
|
||||
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 +468,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
829
lib/screens/lottery.dart
Normal 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
307
lib/screens/lottery.g.dart
Normal 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
|
||||
@@ -237,7 +237,7 @@ class PostCategoryDetailScreen extends HookConsumerWidget {
|
||||
loading: () => ResponseLoadingWidget(),
|
||||
),
|
||||
),
|
||||
),
|
||||
).padding(horizontal: 8),
|
||||
),
|
||||
),
|
||||
const SliverGap(4),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)),
|
||||
);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
|
||||
@@ -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>> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -168,7 +168,7 @@ class MarketplaceStickerPackDetailScreen extends HookConsumerWidget {
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: CloudImageWidget(
|
||||
fileId: sticker.imageId,
|
||||
fileId: sticker.image.id,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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 -
|
||||
|
||||
323
lib/screens/thought/think.dart
Normal file
323
lib/screens/thought/think.dart
Normal 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
156
lib/screens/thought/think.g.dart
Normal file
156
lib/screens/thought/think.g.dart
Normal 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
|
||||
243
lib/screens/thought/think_sheet.dart
Normal file
243
lib/screens/thought/think_sheet.dart
Normal 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
18
lib/services/event_bus.dart
Normal file
18
lib/services/event_bus.dart
Normal 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();
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'account_devices.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$authDevicesHash() => r'feb19238f759921e51c888f8b443a3d7761e68da';
|
||||
String _$authDevicesHash() => r'35735af4ed75b73fe80c8942e53b3bc26a569c01';
|
||||
|
||||
/// See also [authDevices].
|
||||
@ProviderFor(authDevices)
|
||||
|
||||
@@ -36,12 +36,16 @@ const kVerificationMarkColors = [
|
||||
class AccountName extends StatelessWidget {
|
||||
final SnAccount account;
|
||||
final TextStyle? style;
|
||||
final String? textOverride;
|
||||
final bool ignorePermissions;
|
||||
final bool hideVerificationMark;
|
||||
const AccountName({
|
||||
super.key,
|
||||
required this.account,
|
||||
this.style,
|
||||
this.textOverride,
|
||||
this.ignorePermissions = false,
|
||||
this.hideVerificationMark = false,
|
||||
});
|
||||
|
||||
Alignment _parseGradientDirection(String direction) {
|
||||
@@ -177,7 +181,7 @@ class AccountName extends StatelessWidget {
|
||||
child: ShaderMask(
|
||||
shaderCallback: (bounds) => gradient.createShader(bounds),
|
||||
child: Text(
|
||||
account.nick,
|
||||
textOverride ?? account.nick,
|
||||
style: nameStyle.copyWith(color: Colors.white),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@@ -186,7 +190,8 @@ class AccountName extends StatelessWidget {
|
||||
),
|
||||
if (account.perkSubscription != null)
|
||||
StellarMembershipMark(membership: account.perkSubscription!),
|
||||
if (account.profile.verification != null)
|
||||
if (account.profile.verification != null &&
|
||||
!hideVerificationMark)
|
||||
VerificationMark(mark: account.profile.verification!),
|
||||
if (account.automatedId != null)
|
||||
Tooltip(
|
||||
|
||||
@@ -19,7 +19,7 @@ Future<List<SnAccount>> searchAccounts(Ref ref, {required String query}) async {
|
||||
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final response = await apiClient.get(
|
||||
'/id/accounts/search',
|
||||
'/pass/accounts/search',
|
||||
queryParameters: {'query': query},
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'account_picker.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$searchAccountsHash() => r'fa3b8b7d51e14cf40d4116ba0ff0b6955fa0ff54';
|
||||
String _$searchAccountsHash() => r'3b4aa4d7970a1e406c1a0a1dfac2c686e05bc533';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
||||
@@ -31,7 +31,7 @@ class RestorePurchaseSheet extends HookConsumerWidget {
|
||||
try {
|
||||
final client = ref.read(apiClientProvider);
|
||||
await client.post(
|
||||
'/id/subscriptions/order/restore/${selectedProvider.value!}',
|
||||
'/pass/subscriptions/order/restore/${selectedProvider.value!}',
|
||||
data: {'order_id': orderIdController.text.trim()},
|
||||
);
|
||||
|
||||
|
||||
@@ -27,14 +27,18 @@ class CurrentAccountStatusNotifier extends StateNotifier<SnAccountStatus?> {
|
||||
}
|
||||
}
|
||||
|
||||
final currentAccountStatusProvider = StateNotifierProvider<CurrentAccountStatusNotifier, SnAccountStatus?>((ref) {
|
||||
return CurrentAccountStatusNotifier();
|
||||
});
|
||||
final currentAccountStatusProvider =
|
||||
StateNotifierProvider<CurrentAccountStatusNotifier, SnAccountStatus?>((
|
||||
ref,
|
||||
) {
|
||||
return CurrentAccountStatusNotifier();
|
||||
});
|
||||
|
||||
@riverpod
|
||||
Future<SnAccountStatus?> accountStatus(Ref ref, String uname) async {
|
||||
final userInfo = ref.watch(userInfoProvider);
|
||||
if (uname == 'me' || (userInfo.value != null && uname == userInfo.value!.name)) {
|
||||
if (uname == 'me' ||
|
||||
(userInfo.value != null && uname == userInfo.value!.name)) {
|
||||
final local = ref.watch(currentAccountStatusProvider);
|
||||
if (local != null) {
|
||||
return local;
|
||||
@@ -42,7 +46,7 @@ Future<SnAccountStatus?> accountStatus(Ref ref, String uname) async {
|
||||
}
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
try {
|
||||
final resp = await apiClient.get('/id/accounts/$uname/statuses');
|
||||
final resp = await apiClient.get('/pass/accounts/$uname/statuses');
|
||||
return SnAccountStatus.fromJson(resp.data);
|
||||
} catch (err) {
|
||||
if (err is DioException) {
|
||||
@@ -137,9 +141,13 @@ class AccountStatusWidget extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final userInfo = ref.watch(userInfoProvider);
|
||||
final localStatus = ref.watch(currentAccountStatusProvider);
|
||||
final status = (uname == 'me' || (userInfo.value != null && uname == userInfo.value!.name && localStatus != null))
|
||||
? AsyncValue.data(localStatus)
|
||||
: ref.watch(accountStatusProvider(uname));
|
||||
final status =
|
||||
(uname == 'me' ||
|
||||
(userInfo.value != null &&
|
||||
uname == userInfo.value!.name &&
|
||||
localStatus != null))
|
||||
? AsyncValue.data(localStatus)
|
||||
: ref.watch(accountStatusProvider(uname));
|
||||
final account = ref.watch(accountProvider(uname));
|
||||
|
||||
return Padding(
|
||||
@@ -166,16 +174,17 @@ class AccountStatusWidget extends HookConsumerWidget {
|
||||
onLongPress: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('Activity Details'),
|
||||
content: buildActivityDetails(status.value),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Close'),
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: Text('Activity Details'),
|
||||
content: buildActivityDetails(status.value),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Tooltip(
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'status.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$accountStatusHash() => r'abc2f11f0fbaf637efc182cf85ab838936c4d875';
|
||||
String _$accountStatusHash() => r'4cac809808e6f1345dab06dc32d759cfcea13315';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
||||
@@ -33,7 +33,7 @@ class AccountStatusCreationSheet extends HookConsumerWidget {
|
||||
submitting.value = true;
|
||||
final user = ref.watch(userInfoProvider);
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
await apiClient.delete('/id/accounts/me/statuses');
|
||||
await apiClient.delete('/pass/accounts/me/statuses');
|
||||
if (!context.mounted) return;
|
||||
ref.invalidate(accountStatusProvider(user.value!.name));
|
||||
Navigator.pop(context);
|
||||
@@ -50,7 +50,7 @@ class AccountStatusCreationSheet extends HookConsumerWidget {
|
||||
final user = ref.watch(userInfoProvider);
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
await apiClient.request(
|
||||
'/id/accounts/me/statuses',
|
||||
'/pass/accounts/me/statuses',
|
||||
data: {
|
||||
'attitude': attitude.value,
|
||||
'is_invisible': isInvisible.value,
|
||||
|
||||
@@ -30,7 +30,7 @@ part 'stellar_program_tab.g.dart';
|
||||
Future<SnWalletSubscription?> accountStellarSubscription(Ref ref) async {
|
||||
try {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get('/id/subscriptions/fuzzy/solian.stellar');
|
||||
final resp = await client.get('/pass/subscriptions/fuzzy/solian.stellar');
|
||||
return SnWalletSubscription.fromJson(resp.data);
|
||||
} catch (err) {
|
||||
if (err is DioException && err.response?.statusCode == 404) return null;
|
||||
@@ -46,7 +46,7 @@ Future<List<SnWalletGift>> accountSentGifts(
|
||||
}) async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get(
|
||||
'/id/subscriptions/gifts/sent?offset=$offset&take=$take',
|
||||
'/pass/subscriptions/gifts/sent?offset=$offset&take=$take',
|
||||
);
|
||||
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
||||
}
|
||||
@@ -59,7 +59,7 @@ Future<List<SnWalletGift>> accountReceivedGifts(
|
||||
}) async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get(
|
||||
'/id/subscriptions/gifts/received?offset=$offset&take=$take',
|
||||
'/pass/subscriptions/gifts/received?offset=$offset&take=$take',
|
||||
);
|
||||
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
||||
}
|
||||
@@ -67,7 +67,7 @@ Future<List<SnWalletGift>> accountReceivedGifts(
|
||||
@riverpod
|
||||
Future<SnWalletGift> accountGift(Ref ref, String giftId) async {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
final resp = await client.get('/id/subscriptions/gifts/$giftId');
|
||||
final resp = await client.get('/pass/subscriptions/gifts/$giftId');
|
||||
return SnWalletGift.fromJson(resp.data);
|
||||
}
|
||||
|
||||
@@ -388,7 +388,9 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.post('/id/subscriptions/${membership.identifier}/cancel');
|
||||
await client.post(
|
||||
'/pass/subscriptions/${membership.identifier}/cancel',
|
||||
);
|
||||
ref.invalidate(accountStellarSubscriptionProvider);
|
||||
ref.read(userInfoProvider.notifier).fetchUser();
|
||||
if (context.mounted) {
|
||||
@@ -698,7 +700,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
final resp = await client.post(
|
||||
'/id/subscriptions',
|
||||
'/pass/subscriptions',
|
||||
data: {
|
||||
'identifier': tierId,
|
||||
'payment_method': 'solian.wallet',
|
||||
@@ -710,7 +712,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
final subscription = SnWalletSubscription.fromJson(resp.data);
|
||||
if (subscription.status == 1) return;
|
||||
final orderResp = await client.post(
|
||||
'/id/subscriptions/${subscription.identifier}/order',
|
||||
'/pass/subscriptions/${subscription.identifier}/order',
|
||||
);
|
||||
final order = SnWalletOrder.fromJson(orderResp.data);
|
||||
|
||||
@@ -1221,7 +1223,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
final resp = await client.post(
|
||||
'/id/subscriptions/gifts/purchase',
|
||||
'/pass/subscriptions/gifts/purchase',
|
||||
data: {
|
||||
'subscription_identifier': subscriptionId,
|
||||
if (recipientId != null) 'recipient_id': recipientId,
|
||||
@@ -1237,7 +1239,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
if (gift.status == 1) return; // Already paid
|
||||
|
||||
final orderResp = await client.post(
|
||||
'/id/subscriptions/gifts/${gift.id}/order',
|
||||
'/pass/subscriptions/gifts/${gift.id}/order',
|
||||
);
|
||||
final order = SnWalletOrder.fromJson(orderResp.data);
|
||||
|
||||
@@ -1258,7 +1260,9 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
|
||||
// Get the updated gift
|
||||
final giftResp = await client.get('/id/subscriptions/gifts/${gift.id}');
|
||||
final giftResp = await client.get(
|
||||
'/pass/subscriptions/gifts/${gift.id}',
|
||||
);
|
||||
final updatedGift = SnWalletGift.fromJson(giftResp.data);
|
||||
|
||||
if (context.mounted) hideLoadingModal(context);
|
||||
@@ -1367,7 +1371,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
|
||||
// First check if gift can be redeemed
|
||||
final checkResp = await client.get(
|
||||
'/id/subscriptions/gifts/check/$giftCode',
|
||||
'/pass/subscriptions/gifts/check/$giftCode',
|
||||
);
|
||||
final checkData = checkResp.data as Map<String, dynamic>;
|
||||
|
||||
@@ -1379,7 +1383,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
|
||||
// Redeem the gift
|
||||
await client.post(
|
||||
'/id/subscriptions/gifts/redeem',
|
||||
'/pass/subscriptions/gifts/redeem',
|
||||
data: {'gift_code': giftCode},
|
||||
);
|
||||
|
||||
@@ -1424,7 +1428,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
||||
final client = ref.watch(apiClientProvider);
|
||||
try {
|
||||
showLoadingModal(context);
|
||||
await client.post('/id/subscriptions/gifts/${gift.id}/cancel');
|
||||
await client.post('/pass/subscriptions/gifts/${gift.id}/cancel');
|
||||
ref.invalidate(accountSentGiftsProvider);
|
||||
if (context.mounted) {
|
||||
hideLoadingModal(context);
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'stellar_program_tab.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$accountStellarSubscriptionHash() =>
|
||||
r'80abcdefb3868775fd8fe3c980215713efff5948';
|
||||
r'7cdfc7ca29aac240fc8704f4493498d87f307400';
|
||||
|
||||
/// See also [accountStellarSubscription].
|
||||
@ProviderFor(accountStellarSubscription)
|
||||
@@ -27,7 +27,7 @@ final accountStellarSubscriptionProvider =
|
||||
// ignore: unused_element
|
||||
typedef AccountStellarSubscriptionRef =
|
||||
AutoDisposeFutureProviderRef<SnWalletSubscription?>;
|
||||
String _$accountSentGiftsHash() => r'36fdf4e2be3805e8501cca1657d8be27aa891ef4';
|
||||
String _$accountSentGiftsHash() => r'460af8d22e16dc402848cb94e9b8a8a26d023c41';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
@@ -187,7 +187,7 @@ class _AccountSentGiftsProviderElement
|
||||
}
|
||||
|
||||
String _$accountReceivedGiftsHash() =>
|
||||
r'15f6f7e27aa0277b67b02dd72875ba3efd147dfd';
|
||||
r'1208c27cca49e154af073071a197b37a2703f56d';
|
||||
|
||||
/// See also [accountReceivedGifts].
|
||||
@ProviderFor(accountReceivedGifts)
|
||||
@@ -328,7 +328,7 @@ class _AccountReceivedGiftsProviderElement
|
||||
int get take => (origin as AccountReceivedGiftsProvider).take;
|
||||
}
|
||||
|
||||
String _$accountGiftHash() => r'598c5071fff3cc1dd7eb867df48d69fef04543db';
|
||||
String _$accountGiftHash() => r'70ca553e0b84cba9dfbee428f9bf44207138713a';
|
||||
|
||||
/// See also [accountGift].
|
||||
@ProviderFor(accountGift)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user