Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
dfcbfcb31e
|
|||
|
862e3b451b
|
|||
|
62a3ea26e3
|
|||
|
5414dfd4f0
|
|||
|
f2819a9d92
|
|||
|
bc02eb6923
|
|||
|
dd6bc3cc99
|
|||
|
863a84a2a0
|
|||
|
4b1c9b5820
|
|||
|
0237e457fc
|
|||
|
f6f1c99da7
|
|||
|
583902ad52
|
|||
|
cfd2a47064
|
|||
|
5cdeb7bd22
|
|||
|
6e5255550a
|
|||
|
8a9de6f43f
|
|||
|
c9c362d3d1
|
|||
|
617d22847b
|
|||
|
|
3c77a4d5be | ||
|
|
f9061a3dc6 | ||
|
|
e12a26d5c0 | ||
|
|
6b31d28cd3 | ||
|
bff301fdb3
|
|||
|
|
2049ee4401 | ||
|
18c071826f
|
|||
|
5bfc301088
|
|||
|
a39853ba5a
|
|||
|
639417e952
|
|||
|
|
9de4def4d4 | ||
|
fa0051b606
|
|||
|
9d867fd888
|
|||
|
f572f5b462
|
|||
|
a02f2fe3c6
|
|||
|
bc4fddc164
|
|||
|
3d7e7951a2
|
|||
|
41df5f3907
|
|||
|
6487a1ff65
|
|||
|
2e90d243de
|
|||
|
|
1eca95fa78 | ||
|
|
96b87f75f9 | ||
|
e832f3fd93
|
|||
|
aeea90226a
|
|||
|
c36a5eaa73
|
|||
|
6840054a41
|
|||
|
6a0f351114
|
|||
|
c5d667ecf3
|
|||
|
09767e113f
|
|||
|
9ca5c63afd
|
|||
|
fd3c08e054
|
|||
|
72f23a504e
|
|||
|
4898825124
|
|||
|
387d19d85c
|
|||
|
f7b991663f
|
|||
|
3a57f4265b
|
|||
|
d1ee2e5160
|
|||
|
bcd6753ed2
|
|||
|
321ea4458b
|
|||
|
8ad31dad58
|
|||
|
269c17d068
|
|||
|
a9abd777e1
|
|||
|
e24b1fc135
|
|||
|
d5feea52fa
|
|||
|
491252bba9
|
|||
|
4f569fbefd
|
|||
|
476da28b5e
|
|||
|
d639df7623
|
|||
|
e1fc5311d2
|
|||
|
d0e4fde6c2
|
|||
|
9437339b0f
|
|||
|
dd7696132c
|
|||
|
95daa3c28d
|
|||
|
ac5193e1f6
|
|||
|
0328a7736a
|
|||
|
03b332f677
|
|||
|
91b2797fb9
|
BIN
assets/audio/alert.reversed.wav
Normal file
BIN
assets/audio/alert.reversed.wav
Normal file
Binary file not shown.
BIN
assets/audio/alert.wav
Normal file
BIN
assets/audio/alert.wav
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/audio/messages.wav
Normal file
BIN
assets/audio/messages.wav
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/audio/notification.wav
Normal file
BIN
assets/audio/notification.wav
Normal file
Binary file not shown.
@@ -1360,6 +1360,32 @@
|
|||||||
"orCreateWith": "Or\ncreate with",
|
"orCreateWith": "Or\ncreate with",
|
||||||
"unindexedFiles": "Unindexed files",
|
"unindexedFiles": "Unindexed files",
|
||||||
"folder": "Folder",
|
"folder": "Folder",
|
||||||
|
"rootDirectory": "Root Directory",
|
||||||
|
"pathSeparator": " / ",
|
||||||
|
"selectAll": "Select All",
|
||||||
|
"deselectAll": "Deselect All",
|
||||||
|
"createDirectory": "Create Directory",
|
||||||
|
"thisDirectoryIsEmpty": "This directory is empty",
|
||||||
|
"emptyDirectoryHint": "Upload files or create subdirectories to populate this path.\nDirectories are created implicitly when you upload files to them.",
|
||||||
|
"noUnindexedFiles": "No unindexed files",
|
||||||
|
"noUnindexedFilesHint": "All files have been assigned to paths.\nFiles without paths will appear here.",
|
||||||
|
"clearAllRecycledFiles": "Clear All Recycled Files",
|
||||||
|
"clearRecycledFilesDescription": "Permanently delete all marked recycled files to free up space.",
|
||||||
|
"allFiles": "All files",
|
||||||
|
"confirmDeleteSelectedFiles": "Are you sure you want to delete the selected files?",
|
||||||
|
"deleteSelectedFiles": "Delete Selected Files",
|
||||||
|
"confirmClearRecycledFiles": "Are you sure you want to clear all recycled files?",
|
||||||
|
"clearRecycledFiles": "Clear Recycled Files",
|
||||||
|
"failedToUploadFile": "Failed to upload file: {}",
|
||||||
|
"deletedFilesCount": "Deleted {} files.",
|
||||||
|
"failedToDeleteSelectedFiles": "Failed to delete selected files.",
|
||||||
|
"clearedRecycledFilesCount": "Cleared {} recycled files.",
|
||||||
|
"failedToClearRecycledFiles": "Failed to clear recycled files.",
|
||||||
|
"root": "Root",
|
||||||
|
"searchFiles": "Search files...",
|
||||||
|
"selectedCount": "{} selected",
|
||||||
|
"filesSelected": "{} files selected",
|
||||||
|
"fileSelected": "{} file selected",
|
||||||
"clearCompleted": "Clear Completed",
|
"clearCompleted": "Clear Completed",
|
||||||
"uploadSuccess": "Upload successful!",
|
"uploadSuccess": "Upload successful!",
|
||||||
"wouldYouLikeToViewFile": "Would you like to view the file?",
|
"wouldYouLikeToViewFile": "Would you like to view the file?",
|
||||||
@@ -1592,5 +1618,114 @@
|
|||||||
"tasksCount": {
|
"tasksCount": {
|
||||||
"one": "{} task",
|
"one": "{} task",
|
||||||
"other": "{} tasks"
|
"other": "{} tasks"
|
||||||
}
|
},
|
||||||
|
"setAsThumbnail": "Set as thumbnail",
|
||||||
|
"unsetAsThumbnail": "Unset as thumbnail",
|
||||||
|
"sidebar": "Sidebar",
|
||||||
|
"dropFilesHere": "Drop your files here",
|
||||||
|
"dragAndDropToAttach": "Drag your files here to attach it",
|
||||||
|
"customize": "Customize",
|
||||||
|
"dashboardCustomizeTitle": "Customize Dashboard",
|
||||||
|
"dashboardTabVertical": "Vertical",
|
||||||
|
"dashboardTabHorizontal": "Horizontal",
|
||||||
|
"dashboardLayoutVertical": "Vertical Layout",
|
||||||
|
"dashboardLayoutHorizontal": "Horizontal Layout",
|
||||||
|
"dashboardAvailableCards": "Available Cards",
|
||||||
|
"dashboardDisplaySettings": "Display Settings",
|
||||||
|
"dashboardShowSearchBar": "Show Search Bar",
|
||||||
|
"dashboardShowClockAndCountdown": "Show Clock and Countdown",
|
||||||
|
"dashboardResetToDefaults": "Reset to Defaults",
|
||||||
|
"dashboardResetToDefaultsSubtitle": "Restore default dashboard layout and settings",
|
||||||
|
"dashboardResetConfirmMessage": "This will restore the dashboard to its default layout and settings. This action cannot be undone.",
|
||||||
|
"dashboardResetConfirmTitle": "Reset Dashboard",
|
||||||
|
"dashboardCardCheckIn": "Check In",
|
||||||
|
"dashboardCardFortuneGraph": "Fortune Graph",
|
||||||
|
"dashboardCardFortune": "Fortune",
|
||||||
|
"dashboardCardFeaturedPosts": "Featured Posts",
|
||||||
|
"dashboardCardFriends": "Friends",
|
||||||
|
"dashboardCardNotifications": "Notifications",
|
||||||
|
"dashboardCardChats": "Chats",
|
||||||
|
"dashboardCardActivityColumn": "Activity Column",
|
||||||
|
"dashboardCardPostsColumn": "Posts Column",
|
||||||
|
"dashboardCardSocialColumn": "Social Column",
|
||||||
|
"dashboardCardChatsColumn": "Chats Column",
|
||||||
|
"dashboardCardActivityColumnDescription": "Check In, Fortune Graph & Fortune",
|
||||||
|
"dashboardCardPostsColumnDescription": "Featured Posts",
|
||||||
|
"dashboardCardSocialColumnDescription": "Friends & Notifications",
|
||||||
|
"dashboardCardChatsColumnDescription": "Recent Chats",
|
||||||
|
"searchAccountsHint": "Search across the Solar Network and fediverse network.",
|
||||||
|
"fitnessActivity": "Fitness Activity",
|
||||||
|
"loadingFitnessData": "Loading fitness data...",
|
||||||
|
"fitnessDataNotAvailable": "Fitness Data Not Available",
|
||||||
|
"fitnessDataNotAvailableDescription": "Fitness data is only available on iOS and Android devices.",
|
||||||
|
"fitnessPermissionRequired": "Permission Required",
|
||||||
|
"fitnessPermissionRequiredDescription": "To access your fitness data, we need permission to read your health information.",
|
||||||
|
"requestPermission": "Request Permission",
|
||||||
|
"noFitnessData": "No Fitness Data",
|
||||||
|
"noFitnessDataDescription": "No fitness data found. Start tracking your workouts to see them here.",
|
||||||
|
"totalWorkouts": "Total Workouts",
|
||||||
|
"totalDuration": "Total Duration",
|
||||||
|
"totalCalories": "Total Calories",
|
||||||
|
"noWorkoutsOnDate": "No workouts on {}",
|
||||||
|
"noWorkoutsOnDateDescription": "No workouts found for this date.",
|
||||||
|
"workoutsOnDate": "Workouts on {}",
|
||||||
|
"refresh": "Refresh",
|
||||||
|
"fitnessWorkoutTypeBadminton": "Badminton",
|
||||||
|
"fitnessWorkoutTypeBaseball": "Baseball",
|
||||||
|
"fitnessWorkoutTypeBasketball": "Basketball",
|
||||||
|
"fitnessWorkoutTypeBiking": "Biking",
|
||||||
|
"fitnessWorkoutTypeCalisthenics": "Calisthenics",
|
||||||
|
"fitnessWorkoutTypeCricket": "Cricket",
|
||||||
|
"fitnessWorkoutTypeDancing": "Dancing",
|
||||||
|
"fitnessWorkoutTypeElliptical": "Elliptical",
|
||||||
|
"fitnessWorkoutTypeFencing": "Fencing",
|
||||||
|
"fitnessWorkoutTypeFrisbeeDisc": "Frisbee Disc",
|
||||||
|
"fitnessWorkoutTypeGolf": "Golf",
|
||||||
|
"fitnessWorkoutTypeGymnastics": "Gymnastics",
|
||||||
|
"fitnessWorkoutTypeHiking": "Hiking",
|
||||||
|
"fitnessWorkoutTypeHockey": "Hockey",
|
||||||
|
"fitnessWorkoutTypeJumpRope": "Jump Rope",
|
||||||
|
"fitnessWorkoutTypeKickboxing": "Kickboxing",
|
||||||
|
"fitnessWorkoutTypeLacrosse": "Lacrosse",
|
||||||
|
"fitnessWorkoutTypeMartialArts": "Martial Arts",
|
||||||
|
"fitnessWorkoutTypeMindAndBody": "Mind and Body",
|
||||||
|
"fitnessWorkoutTypePilates": "Pilates",
|
||||||
|
"fitnessWorkoutTypeRowing": "Rowing",
|
||||||
|
"fitnessWorkoutTypeRowingMachine": "Rowing Machine",
|
||||||
|
"fitnessWorkoutTypeRugby": "Rugby",
|
||||||
|
"fitnessWorkoutTypeRunning": "Running",
|
||||||
|
"fitnessWorkoutTypeSailing": "Sailing",
|
||||||
|
"fitnessWorkoutTypeSkiing": "Skiing",
|
||||||
|
"fitnessWorkoutTypeSnowSports": "Snow Sports",
|
||||||
|
"fitnessWorkoutTypeSoftball": "Softball",
|
||||||
|
"fitnessWorkoutTypeStairClimbing": "Stair Climbing",
|
||||||
|
"fitnessWorkoutTypeStairClimbingMachine": "Stair Climbing Machine",
|
||||||
|
"fitnessWorkoutTypeStepTraining": "Step Training",
|
||||||
|
"fitnessWorkoutTypeSurfing": "Surfing",
|
||||||
|
"fitnessWorkoutTypeSwimming": "Swimming",
|
||||||
|
"fitnessWorkoutTypeTableTennis": "Table Tennis",
|
||||||
|
"fitnessWorkoutTypeTennis": "Tennis",
|
||||||
|
"fitnessWorkoutTypeCrossTraining": "Cross Training",
|
||||||
|
"fitnessWorkoutTypeCurling": "Curling",
|
||||||
|
"fitnessWorkoutTypeCrossCountrySkiing": "Cross Country Skiing",
|
||||||
|
"fitnessWorkoutTypeEquestrianSports": "Equestrian Sports",
|
||||||
|
"fitnessWorkoutTypeFishing": "Fishing",
|
||||||
|
"fitnessWorkoutTypeFunctionalStrengthTraining": "Functional Strength Training",
|
||||||
|
"fitnessWorkoutTypeHandCycling": "Hand Cycling",
|
||||||
|
"fitnessWorkoutTypeMixedCardio": "Mixed Cardio",
|
||||||
|
"fitnessWorkoutTypeOther": "Other",
|
||||||
|
"fitnessWorkoutTypePaddleSports": "Paddle Sports",
|
||||||
|
"fitnessWorkoutTypePickleball": "Pickleball",
|
||||||
|
"fitnessWorkoutTypeRacquetball": "Racquetball",
|
||||||
|
"fitnessWorkoutTypeRockClimbing": "Rock Climbing",
|
||||||
|
"fitnessWorkoutTypeSkating": "Skating",
|
||||||
|
"fitnessWorkoutTypeSnowboarding": "Snowboarding",
|
||||||
|
"fitnessWorkoutTypeSoccer": "Soccer",
|
||||||
|
"fitnessWorkoutTypeSquash": "Squash",
|
||||||
|
"fitnessWorkoutTypeStrengthTraining": "Strength Training",
|
||||||
|
"fitnessWorkoutTypeVolleyball": "Volleyball",
|
||||||
|
"fitnessWorkoutTypeWalking": "Walking",
|
||||||
|
"fitnessWorkoutTypeWeightlifting": "Weightlifting",
|
||||||
|
"fitnessWorkoutTypeYoga": "Yoga",
|
||||||
|
"fitnessWorkoutTypeDefault": "Fitness"
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -191,6 +191,7 @@
|
|||||||
"statusActivityEndedTitle": "{} 正在 {} {} 直到 {}",
|
"statusActivityEndedTitle": "{} 正在 {} {} 直到 {}",
|
||||||
"appSettings": "应用设置",
|
"appSettings": "应用设置",
|
||||||
"accountSettings": "账号设置",
|
"accountSettings": "账号设置",
|
||||||
|
"accounts": "账号",
|
||||||
"settings": "设置",
|
"settings": "设置",
|
||||||
"language": "语言",
|
"language": "语言",
|
||||||
"accountLanguageHint": "此语言将用于电子邮件和推送通知。",
|
"accountLanguageHint": "此语言将用于电子邮件和推送通知。",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
BIN
assets/midi/never-gonna-give-you-up.mid
Normal file
BIN
assets/midi/never-gonna-give-you-up.mid
Normal file
Binary file not shown.
153
ios/Podfile.lock
153
ios/Podfile.lock
@@ -1,5 +1,5 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- Alamofire (5.11.0)
|
- Alamofire (5.11.1)
|
||||||
- audio_session (0.0.1):
|
- audio_session (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
@@ -44,91 +44,89 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- file_saver (0.0.1):
|
- file_saver (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Firebase/CoreOnly (12.6.0):
|
- Firebase/CoreOnly (12.8.0):
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- Firebase/Crashlytics (12.6.0):
|
- Firebase/Crashlytics (12.8.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseCrashlytics (~> 12.6.0)
|
- FirebaseCrashlytics (~> 12.8.0)
|
||||||
- Firebase/Messaging (12.6.0):
|
- Firebase/Messaging (12.8.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseMessaging (~> 12.6.0)
|
- FirebaseMessaging (~> 12.8.0)
|
||||||
- firebase_analytics (12.1.0):
|
- firebase_analytics (12.1.1):
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- FirebaseAnalytics (= 12.6.0)
|
- FirebaseAnalytics (= 12.8.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_core (4.3.0):
|
- firebase_core (4.4.0):
|
||||||
- Firebase/CoreOnly (= 12.6.0)
|
- Firebase/CoreOnly (= 12.8.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_crashlytics (5.0.6):
|
- firebase_crashlytics (5.0.7):
|
||||||
- Firebase/Crashlytics (= 12.6.0)
|
- Firebase/Crashlytics (= 12.8.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_messaging (16.1.0):
|
- firebase_messaging (16.1.1):
|
||||||
- Firebase/Messaging (= 12.6.0)
|
- Firebase/Messaging (= 12.8.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- FirebaseAnalytics (12.6.0):
|
- FirebaseAnalytics (12.8.0):
|
||||||
- FirebaseAnalytics/Default (= 12.6.0)
|
- FirebaseAnalytics/Default (= 12.8.0)
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- FirebaseInstallations (~> 12.6.0)
|
- FirebaseInstallations (~> 12.8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/Network (~> 8.1)
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- FirebaseAnalytics/Default (12.6.0):
|
- FirebaseAnalytics/Default (12.8.0):
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- FirebaseInstallations (~> 12.6.0)
|
- FirebaseInstallations (~> 12.8.0)
|
||||||
- GoogleAppMeasurement/Default (= 12.6.0)
|
- GoogleAppMeasurement/Default (= 12.8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/Network (~> 8.1)
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- FirebaseCore (12.6.0):
|
- FirebaseCore (12.8.0):
|
||||||
- FirebaseCoreInternal (~> 12.6.0)
|
- FirebaseCoreInternal (~> 12.8.0)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- GoogleUtilities/Logger (~> 8.1)
|
- GoogleUtilities/Logger (~> 8.1)
|
||||||
- FirebaseCoreExtension (12.6.0):
|
- FirebaseCoreExtension (12.8.0):
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- FirebaseCoreInternal (12.6.0):
|
- FirebaseCoreInternal (12.8.0):
|
||||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
- FirebaseCrashlytics (12.6.0):
|
- FirebaseCrashlytics (12.8.0):
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- FirebaseInstallations (~> 12.6.0)
|
- FirebaseInstallations (~> 12.8.0)
|
||||||
- FirebaseRemoteConfigInterop (~> 12.6.0)
|
- FirebaseRemoteConfigInterop (~> 12.8.0)
|
||||||
- FirebaseSessions (~> 12.6.0)
|
- FirebaseSessions (~> 12.8.0)
|
||||||
- GoogleDataTransport (~> 10.1)
|
- GoogleDataTransport (~> 10.1)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- PromisesObjC (~> 2.4)
|
- PromisesObjC (~> 2.4)
|
||||||
- FirebaseInstallations (12.6.0):
|
- FirebaseInstallations (12.8.0):
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
- PromisesObjC (~> 2.4)
|
- PromisesObjC (~> 2.4)
|
||||||
- FirebaseMessaging (12.6.0):
|
- FirebaseMessaging (12.8.0):
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- FirebaseInstallations (~> 12.6.0)
|
- FirebaseInstallations (~> 12.8.0)
|
||||||
- GoogleDataTransport (~> 10.1)
|
- GoogleDataTransport (~> 10.1)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- GoogleUtilities/Reachability (~> 8.1)
|
- GoogleUtilities/Reachability (~> 8.1)
|
||||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- FirebaseRemoteConfigInterop (12.6.0)
|
- FirebaseRemoteConfigInterop (12.8.0)
|
||||||
- FirebaseSessions (12.6.0):
|
- FirebaseSessions (12.8.0):
|
||||||
- FirebaseCore (~> 12.6.0)
|
- FirebaseCore (~> 12.8.0)
|
||||||
- FirebaseCoreExtension (~> 12.6.0)
|
- FirebaseCoreExtension (~> 12.8.0)
|
||||||
- FirebaseInstallations (~> 12.6.0)
|
- FirebaseInstallations (~> 12.8.0)
|
||||||
- GoogleDataTransport (~> 10.1)
|
- GoogleDataTransport (~> 10.1)
|
||||||
- GoogleUtilities/Environment (~> 8.1)
|
- GoogleUtilities/Environment (~> 8.1)
|
||||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- PromisesSwift (~> 2.1)
|
- PromisesSwift (~> 2.1)
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_app_intents (0.1.0):
|
|
||||||
- Flutter
|
|
||||||
- flutter_app_update (0.0.1):
|
- flutter_app_update (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_inappwebview_ios (0.0.1):
|
- flutter_inappwebview_ios (0.0.1):
|
||||||
@@ -163,23 +161,23 @@ PODS:
|
|||||||
- GoogleUtilities/Logger (~> 8.1)
|
- GoogleUtilities/Logger (~> 8.1)
|
||||||
- GoogleUtilities/Network (~> 8.1)
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- GoogleAppMeasurement/Core (12.6.0):
|
- GoogleAppMeasurement/Core (12.8.0):
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/Network (~> 8.1)
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- GoogleAppMeasurement/Default (12.6.0):
|
- GoogleAppMeasurement/Default (12.8.0):
|
||||||
- GoogleAdsOnDeviceConversion (~> 3.2.0)
|
- GoogleAdsOnDeviceConversion (~> 3.2.0)
|
||||||
- GoogleAppMeasurement/Core (= 12.6.0)
|
- GoogleAppMeasurement/Core (= 12.8.0)
|
||||||
- GoogleAppMeasurement/IdentitySupport (= 12.6.0)
|
- GoogleAppMeasurement/IdentitySupport (= 12.8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/Network (~> 8.1)
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- GoogleAppMeasurement/IdentitySupport (12.6.0):
|
- GoogleAppMeasurement/IdentitySupport (12.8.0):
|
||||||
- GoogleAppMeasurement/Core (= 12.6.0)
|
- GoogleAppMeasurement/Core (= 12.8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||||
- GoogleUtilities/Network (~> 8.1)
|
- GoogleUtilities/Network (~> 8.1)
|
||||||
@@ -215,6 +213,8 @@ PODS:
|
|||||||
- GoogleUtilities/UserDefaults (8.1.0):
|
- GoogleUtilities/UserDefaults (8.1.0):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
|
- health (13.1.4):
|
||||||
|
- Flutter
|
||||||
- image_picker_ios (0.0.1):
|
- image_picker_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- in_app_review (2.0.0):
|
- in_app_review (2.0.0):
|
||||||
@@ -264,9 +264,6 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- pasteboard (0.0.1):
|
- pasteboard (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- FlutterMacOS
|
|
||||||
- permission_handler_apple (9.3.0):
|
- permission_handler_apple (9.3.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- pointer_interceptor_ios (0.0.1):
|
- pointer_interceptor_ios (0.0.1):
|
||||||
@@ -280,7 +277,7 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- receive_sharing_intent (1.8.1):
|
- receive_sharing_intent (1.8.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- record_ios (1.1.0):
|
- record_ios (1.2.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- SDWebImage (5.21.5):
|
- SDWebImage (5.21.5):
|
||||||
- SDWebImage/Core (= 5.21.5)
|
- SDWebImage/Core (= 5.21.5)
|
||||||
@@ -349,7 +346,6 @@ DEPENDENCIES:
|
|||||||
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
||||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_app_intents (from `.symlinks/plugins/flutter_app_intents/ios`)
|
|
||||||
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
|
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
|
||||||
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
|
||||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||||
@@ -360,6 +356,7 @@ DEPENDENCIES:
|
|||||||
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
|
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
|
||||||
- flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`)
|
- flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`)
|
||||||
- gal (from `.symlinks/plugins/gal/darwin`)
|
- gal (from `.symlinks/plugins/gal/darwin`)
|
||||||
|
- health (from `.symlinks/plugins/health/ios`)
|
||||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
||||||
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
||||||
@@ -373,7 +370,6 @@ DEPENDENCIES:
|
|||||||
- native_exif (from `.symlinks/plugins/native_exif/ios`)
|
- native_exif (from `.symlinks/plugins/native_exif/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
||||||
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
|
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
|
||||||
@@ -447,8 +443,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_app_intents:
|
|
||||||
:path: ".symlinks/plugins/flutter_app_intents/ios"
|
|
||||||
flutter_app_update:
|
flutter_app_update:
|
||||||
:path: ".symlinks/plugins/flutter_app_update/ios"
|
:path: ".symlinks/plugins/flutter_app_update/ios"
|
||||||
flutter_inappwebview_ios:
|
flutter_inappwebview_ios:
|
||||||
@@ -469,6 +463,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/flutter_webrtc/ios"
|
:path: ".symlinks/plugins/flutter_webrtc/ios"
|
||||||
gal:
|
gal:
|
||||||
:path: ".symlinks/plugins/gal/darwin"
|
:path: ".symlinks/plugins/gal/darwin"
|
||||||
|
health:
|
||||||
|
:path: ".symlinks/plugins/health/ios"
|
||||||
image_picker_ios:
|
image_picker_ios:
|
||||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||||
in_app_review:
|
in_app_review:
|
||||||
@@ -491,8 +487,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
pasteboard:
|
pasteboard:
|
||||||
:path: ".symlinks/plugins/pasteboard/ios"
|
:path: ".symlinks/plugins/pasteboard/ios"
|
||||||
path_provider_foundation:
|
|
||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
pointer_interceptor_ios:
|
pointer_interceptor_ios:
|
||||||
@@ -529,7 +523,7 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Alamofire: bd5e7b23a1a750975288482c1831d71e74415f86
|
Alamofire: eec6cd8f73b242b59e34153a606a909eb9864b14
|
||||||
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
|
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
||||||
@@ -538,22 +532,21 @@ SPEC CHECKSUMS:
|
|||||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||||
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||||
Firebase: a451a7b61536298fd5cbfe3a746fd40443a50679
|
Firebase: 9a58fdbc9d8655ed7b79a19cf9690bb007d3d46d
|
||||||
firebase_analytics: 4f9cca09e65f6c2944a862c6dc86f6bed9fb769c
|
firebase_analytics: b5a19eaf3e4bf4187b0815ef4850b8916e2bc549
|
||||||
firebase_core: ba00a168e719694f38960502ceb560285603d073
|
firebase_core: ee30637e6744af8e0c12a6a1e8a9718506ec2398
|
||||||
firebase_crashlytics: 13f4b77e9ce2a84b1f8ea07f293db5b6213ce1cf
|
firebase_crashlytics: 28b8f39df8104131376393e6af658b8b77dd120f
|
||||||
firebase_messaging: bf0e29321927edc02a563c984dbfa5b063864b15
|
firebase_messaging: 343de01a8d3e18b60df0c6d37f7174c44ae38e02
|
||||||
FirebaseAnalytics: d0a97a0db6425e5a5d966340b87f92ca7b13a557
|
FirebaseAnalytics: f20bbad8cb7f65d8a5eaefeb424ae8800a31bdfc
|
||||||
FirebaseCore: 0e38ad5d62d980a47a64b8e9301ffa311457be04
|
FirebaseCore: 0dbad74bda10b8fb9ca34ad8f375fb9dd3ebef7c
|
||||||
FirebaseCoreExtension: 032fd6f8509e591fda8cb76f6651f20d926b121f
|
FirebaseCoreExtension: 6605938d51f765d8b18bfcafd2085276a252bee2
|
||||||
FirebaseCoreInternal: 69bf1306a05b8ac43004f6cc1f804bb7b05b229e
|
FirebaseCoreInternal: fe5fa466aeb314787093a7dce9f0beeaad5a2a21
|
||||||
FirebaseCrashlytics: 3d6248c50726ee7832aef0e53cb84c9e64d9fa7e
|
FirebaseCrashlytics: fb31c6907e5b52aa252668394d3f1ab326df1511
|
||||||
FirebaseInstallations: 631b38da2e11a83daa4bfb482f79d286a5dfa7ad
|
FirebaseInstallations: 6a14ab3d694ebd9f839c48d330da5547e9ca9dc0
|
||||||
FirebaseMessaging: a61bc42dcab3f7a346d94bbb54dab2c9435b18b2
|
FirebaseMessaging: 7f42cfd10ec64181db4e01b305a613791c8e782c
|
||||||
FirebaseRemoteConfigInterop: 3443b8cb8fffd76bb3e03b2a84bfd3db952fcda4
|
FirebaseRemoteConfigInterop: 869ddca16614f979e5c931ece11fbb0b8729ed41
|
||||||
FirebaseSessions: 2e8f808347e665dff3e5843f275715f07045297d
|
FirebaseSessions: d614ca154c63dbbc6c10d6c38259c2162c4e7c9b
|
||||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||||
flutter_app_intents: e77f999f398c841ab584a1925dbce33ee0168fb5
|
|
||||||
flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9
|
flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9
|
||||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||||
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
||||||
@@ -565,9 +558,10 @@ SPEC CHECKSUMS:
|
|||||||
flutter_webrtc: c3e21fc0dcd9d8eb246ae4d5256fcbeb2f5ecd22
|
flutter_webrtc: c3e21fc0dcd9d8eb246ae4d5256fcbeb2f5ecd22
|
||||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||||
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
|
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
|
||||||
GoogleAppMeasurement: 3bf40aff49a601af5da1c3345702fcb4991d35ee
|
GoogleAppMeasurement: 72c9a682fec6290327ea5e3c4b829b247fcb2c17
|
||||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||||
|
health: 32d2fbc7f26f9a2388d1a514ce168adbfa5bda65
|
||||||
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
||||||
in_app_review: 7dd1ea365263f834b8464673f9df72c80c17c937
|
in_app_review: 7dd1ea365263f834b8464673f9df72c80c17c937
|
||||||
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
||||||
@@ -585,7 +579,6 @@ SPEC CHECKSUMS:
|
|||||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||||
pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c
|
pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c
|
||||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
|
||||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||||
pointer_interceptor_ios: da06a662d5bfd329602b45b2ab41bc0fb5fdb0f0
|
pointer_interceptor_ios: da06a662d5bfd329602b45b2ab41bc0fb5fdb0f0
|
||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
@@ -593,7 +586,7 @@ SPEC CHECKSUMS:
|
|||||||
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
||||||
quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779
|
quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779
|
||||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||||
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
record_ios: 412daca2350b228e698fffcd08f1f94ceb1e3844
|
||||||
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
|
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
|
||||||
sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b
|
sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b
|
||||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 77;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
7301DB052F08D99C008390F3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7301DB042F08D99C008390F3 /* SwiftUI.framework */; };
|
7301DB052F08D99C008390F3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7301DB042F08D99C008390F3 /* SwiftUI.framework */; };
|
||||||
7301DB102F08D99D008390F3 /* SolianWidgetExtensionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 7301DB012F08D99C008390F3 /* SolianWidgetExtensionExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
7301DB102F08D99D008390F3 /* SolianWidgetExtensionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 7301DB012F08D99C008390F3 /* SolianWidgetExtensionExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
7310A7DF2EB10963002C0FD3 /* Solian Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7310A7D42EB10962002C0FD3 /* Solian Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
7310A7DF2EB10963002C0FD3 /* Solian Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7310A7D42EB10962002C0FD3 /* Solian Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
73595B1B2F17FF8000AAD53C /* SfxMessage.caf in Resources */ = {isa = PBXBuildFile; fileRef = 73595B162F17FF8000AAD53C /* SfxMessage.caf */; };
|
||||||
|
73595B1C2F17FF8000AAD53C /* SfxNotification.caf in Resources */ = {isa = PBXBuildFile; fileRef = 73595B172F17FF8000AAD53C /* SfxNotification.caf */; };
|
||||||
|
73595B832F1803D300AAD53C /* SfxNotification.caf in Resources */ = {isa = PBXBuildFile; fileRef = 73595B172F17FF8000AAD53C /* SfxNotification.caf */; };
|
||||||
|
73595B842F1803D300AAD53C /* SfxMessage.caf in Resources */ = {isa = PBXBuildFile; fileRef = 73595B162F17FF8000AAD53C /* SfxMessage.caf */; };
|
||||||
73ACDFAD2E3D0E6100B63535 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */; };
|
73ACDFAD2E3D0E6100B63535 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */; };
|
||||||
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
@@ -133,6 +137,8 @@
|
|||||||
7301DB042F08D99C008390F3 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
7301DB042F08D99C008390F3 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||||
7301DB162F08D9A5008390F3 /* SolianWidgetExtensionExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SolianWidgetExtensionExtension.entitlements; sourceTree = "<group>"; };
|
7301DB162F08D9A5008390F3 /* SolianWidgetExtensionExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SolianWidgetExtensionExtension.entitlements; sourceTree = "<group>"; };
|
||||||
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Solian Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Solian Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
73595B162F17FF8000AAD53C /* SfxMessage.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = SfxMessage.caf; sourceTree = "<group>"; };
|
||||||
|
73595B172F17FF8000AAD53C /* SfxNotification.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = SfxNotification.caf; sourceTree = "<group>"; };
|
||||||
737E920B2DB6A9FF00BE9CDB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
737E920B2DB6A9FF00BE9CDB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
||||||
@@ -216,8 +222,6 @@
|
|||||||
};
|
};
|
||||||
7310A7D52EB10962002C0FD3 /* Solian Watch App */ = {
|
7310A7D52EB10962002C0FD3 /* Solian Watch App */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
exceptions = (
|
|
||||||
);
|
|
||||||
path = "Solian Watch App";
|
path = "Solian Watch App";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -396,6 +400,8 @@
|
|||||||
91E124CE95BCB4DCD890160D /* Pods */,
|
91E124CE95BCB4DCD890160D /* Pods */,
|
||||||
498A09270B73B217F0279168 /* Frameworks */,
|
498A09270B73B217F0279168 /* Frameworks */,
|
||||||
9AE244813FCDFAA941430393 /* GoogleService-Info.plist */,
|
9AE244813FCDFAA941430393 /* GoogleService-Info.plist */,
|
||||||
|
73595B162F17FF8000AAD53C /* SfxMessage.caf */,
|
||||||
|
73595B172F17FF8000AAD53C /* SfxNotification.caf */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -695,6 +701,8 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
73595B1B2F17FF8000AAD53C /* SfxMessage.caf in Resources */,
|
||||||
|
73595B1C2F17FF8000AAD53C /* SfxNotification.caf in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -703,6 +711,8 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
|
73595B832F1803D300AAD53C /* SfxNotification.caf in Resources */,
|
||||||
|
73595B842F1803D300AAD53C /* SfxMessage.caf in Resources */,
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
@@ -759,10 +769,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
@@ -820,10 +834,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
@@ -874,10 +892,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks.sh\"\n";
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import WidgetKit
|
|||||||
import UIKit
|
import UIKit
|
||||||
import WatchConnectivity
|
import WatchConnectivity
|
||||||
import AppIntents
|
import AppIntents
|
||||||
import flutter_app_intents
|
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
@@ -35,10 +34,8 @@ import flutter_app_intents
|
|||||||
|
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
|
||||||
// Setup widget sync method channel
|
|
||||||
setupWidgetSyncChannel()
|
setupWidgetSyncChannel()
|
||||||
|
|
||||||
// Always initialize and retain a strong reference
|
|
||||||
if WCSession.isSupported() {
|
if WCSession.isSupported() {
|
||||||
AppDelegate.sharedWatchConnectivityService = WatchConnectivityService.shared
|
AppDelegate.sharedWatchConnectivityService = WatchConnectivityService.shared
|
||||||
} else {
|
} else {
|
||||||
@@ -84,8 +81,6 @@ final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
|||||||
session.activate()
|
session.activate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - WCSessionDelegate
|
|
||||||
|
|
||||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||||
if let error = error {
|
if let error = error {
|
||||||
print("[iOS] WCSession activation failed: \(error.localizedDescription)")
|
print("[iOS] WCSession activation failed: \(error.localizedDescription)")
|
||||||
@@ -140,412 +135,3 @@ final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - App Intents
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct OpenChatIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Open Chat"
|
|
||||||
static var description = IntentDescription("Open a specific chat room")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = true
|
|
||||||
|
|
||||||
@Parameter(title: "Channel ID")
|
|
||||||
var channelId: String?
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "open_chat",
|
|
||||||
parameters: ["channelId": channelId ?? ""]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Chat opened"
|
|
||||||
return .result(value: value)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to open chat"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct OpenPostIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Open Post"
|
|
||||||
static var description = IntentDescription("Open a specific post")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = true
|
|
||||||
|
|
||||||
@Parameter(title: "Post ID")
|
|
||||||
var postId: String?
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "open_post",
|
|
||||||
parameters: ["postId": postId ?? ""]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Post opened"
|
|
||||||
return .result(value: value)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to open post"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct OpenComposeIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Open Compose"
|
|
||||||
static var description = IntentDescription("Open compose post screen")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = true
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "open_compose",
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Compose screen opened"
|
|
||||||
return .result(value: value)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to open compose"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct ComposePostIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Compose Post"
|
|
||||||
static var description = IntentDescription("Create a new post")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = true
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "compose_post",
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Compose screen opened"
|
|
||||||
return .result(value: value)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to compose post"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct SearchContentIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Search Content"
|
|
||||||
static var description = IntentDescription("Search for content")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = true
|
|
||||||
|
|
||||||
@Parameter(title: "Search Query")
|
|
||||||
var query: String?
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "search_content",
|
|
||||||
parameters: ["query": query ?? ""]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Search opened"
|
|
||||||
return .result(value: value)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to search"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct ViewNotificationsIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "View Notifications"
|
|
||||||
static var description = IntentDescription("View notifications")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = true
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & OpensIntent {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "view_notifications",
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Notifications opened"
|
|
||||||
return .result(value: value)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to view notifications"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct CheckNotificationsIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Check Notifications"
|
|
||||||
static var description = IntentDescription("Check notification count")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = false
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "check_notifications",
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "You have new notifications"
|
|
||||||
return .result(
|
|
||||||
value: value,
|
|
||||||
dialog: "\(value)"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to check notifications"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct SendMessageIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Send Message"
|
|
||||||
static var description = IntentDescription("Send a message to a chat channel")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = false
|
|
||||||
|
|
||||||
@Parameter(title: "Channel ID")
|
|
||||||
var channelId: String?
|
|
||||||
|
|
||||||
@Parameter(title: "Message Content")
|
|
||||||
var content: String?
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
|
||||||
guard let channelId = channelId, !channelId.isEmpty else {
|
|
||||||
throw AppIntentError.executionFailed("Channel ID is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let content = content, !content.isEmpty else {
|
|
||||||
throw AppIntentError.executionFailed("Message content is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "send_message",
|
|
||||||
parameters: ["channelId": channelId, "content": content]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Message sent"
|
|
||||||
return .result(
|
|
||||||
value: value,
|
|
||||||
dialog: "\(value)"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to send message"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct ReadMessagesIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Read Messages"
|
|
||||||
static var description = IntentDescription("Read recent messages from a chat channel")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = false
|
|
||||||
|
|
||||||
@Parameter(title: "Channel ID")
|
|
||||||
var channelId: String?
|
|
||||||
|
|
||||||
@Parameter(title: "Number of Messages", default: "5")
|
|
||||||
var limit: String?
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
|
||||||
guard let channelId = channelId, !channelId.isEmpty else {
|
|
||||||
throw AppIntentError.executionFailed("Channel ID is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
let limit = limit ?? "5"
|
|
||||||
var parameters: [String: Any] = ["channelId": channelId]
|
|
||||||
parameters["limit"] = limit
|
|
||||||
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "read_messages",
|
|
||||||
parameters: parameters
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Messages retrieved"
|
|
||||||
return .result(
|
|
||||||
value: value,
|
|
||||||
dialog: "\(value)"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to read messages"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct CheckUnreadChatsIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Check Unread Chats"
|
|
||||||
static var description = IntentDescription("Check number of unread chat messages")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = false
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "check_unread_chats",
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "No unread messages"
|
|
||||||
return .result(
|
|
||||||
value: value,
|
|
||||||
dialog: "\(value)"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to check unread chats"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct MarkNotificationsReadIntent: AppIntent {
|
|
||||||
static var title: LocalizedStringResource = "Mark Notifications Read"
|
|
||||||
static var description = IntentDescription("Mark all notifications as read")
|
|
||||||
static var isDiscoverable = true
|
|
||||||
static var openAppWhenRun = false
|
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
|
|
||||||
let plugin = FlutterAppIntentsPlugin.shared
|
|
||||||
let result = await plugin.handleIntentInvocation(
|
|
||||||
identifier: "mark_notifications_read",
|
|
||||||
parameters: [:]
|
|
||||||
)
|
|
||||||
|
|
||||||
if let success = result["success"] as? Bool, success {
|
|
||||||
let value = result["value"] as? String ?? "Notifications marked as read"
|
|
||||||
return .result(
|
|
||||||
value: value,
|
|
||||||
dialog: "\(value)"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let errorMessage = result["error"] as? String ?? "Failed to mark notifications as read"
|
|
||||||
throw AppIntentError.executionFailed(errorMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AppIntentError: Error {
|
|
||||||
case executionFailed(String)
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(iOS 16.0, *)
|
|
||||||
struct AppShortcuts: AppShortcutsProvider {
|
|
||||||
static var appShortcuts: [AppShortcut] {
|
|
||||||
return [
|
|
||||||
// Open chat
|
|
||||||
AppShortcut(
|
|
||||||
intent: OpenChatIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Open chat with \(.applicationName)",
|
|
||||||
"Go to chat using \(.applicationName)",
|
|
||||||
"Show chat in \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Open post
|
|
||||||
AppShortcut(
|
|
||||||
intent: OpenPostIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Open post with \(.applicationName)",
|
|
||||||
"Show post using \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Compose
|
|
||||||
AppShortcut(
|
|
||||||
intent: OpenComposeIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Open compose with \(.applicationName)",
|
|
||||||
"New post using \(.applicationName)",
|
|
||||||
"Write post in \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Search
|
|
||||||
AppShortcut(
|
|
||||||
intent: SearchContentIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Search in \(.applicationName)",
|
|
||||||
"Find content using \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Check notifications
|
|
||||||
AppShortcut(
|
|
||||||
intent: CheckNotificationsIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Check notifications with \(.applicationName)",
|
|
||||||
"Get notifications using \(.applicationName)",
|
|
||||||
"Do I have notifications in \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Send message
|
|
||||||
AppShortcut(
|
|
||||||
intent: SendMessageIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Send message with \(.applicationName)",
|
|
||||||
"Post message using \(.applicationName)",
|
|
||||||
"Send text using \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Read messages
|
|
||||||
AppShortcut(
|
|
||||||
intent: ReadMessagesIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Read messages with \(.applicationName)",
|
|
||||||
"Get chat using \(.applicationName)",
|
|
||||||
"Show messages with \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Check unread chats
|
|
||||||
AppShortcut(
|
|
||||||
intent: CheckUnreadChatsIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Check unread chats with \(.applicationName)",
|
|
||||||
"Do I have messages using \(.applicationName)",
|
|
||||||
"Get unread messages with \(.applicationName)"
|
|
||||||
]
|
|
||||||
),
|
|
||||||
// Mark notifications read
|
|
||||||
AppShortcut(
|
|
||||||
intent: MarkNotificationsReadIntent(),
|
|
||||||
phrases: [
|
|
||||||
"Mark notifications read with \(.applicationName)",
|
|
||||||
"Clear notifications using \(.applicationName)",
|
|
||||||
"Mark all read with \(.applicationName)"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -55,16 +55,6 @@
|
|||||||
<false/>
|
<false/>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSCalendarsUsageDescription</key>
|
|
||||||
<string>Grant access to Calander help us to shows Solar Calander with your own events.</string>
|
|
||||||
<key>NSCameraUsageDescription</key>
|
|
||||||
<string>Grant access to Camera will allow Solian take photo or video for your post.</string>
|
|
||||||
<key>NSFaceIDUsageDescription</key>
|
|
||||||
<string>Allow the Solar Network verify your ownership of the logged in account and continue your action quickly.</string>
|
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
|
||||||
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
|
||||||
<key>NSSpeechRecognitionUsageDescription</key>
|
|
||||||
<string>Solian uses speech recognition for Siri integration</string>
|
|
||||||
<key>NSAppIntentsConfiguration</key>
|
<key>NSAppIntentsConfiguration</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAppIntentsPackage</key>
|
<key>NSAppIntentsPackage</key>
|
||||||
@@ -75,10 +65,25 @@
|
|||||||
<key>NSAppIntentsSupported</key>
|
<key>NSAppIntentsSupported</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>NSCalendarsUsageDescription</key>
|
||||||
|
<string>Grant access to Calander help us to shows Solar Calander with your own events.</string>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>Grant access to Camera will allow Solian take photo or video for your post.</string>
|
||||||
|
<key>NSFaceIDUsageDescription</key>
|
||||||
|
<string>Allow the Solar Network verify your ownership of the logged in account and continue
|
||||||
|
your action quickly.</string>
|
||||||
|
<key>NSHealthShareUsageDescription</key>
|
||||||
|
<string>Allow us to share your fitness data with your friends.</string>
|
||||||
|
<key>NSHealthUpdateUsageDescription</key>
|
||||||
|
<string>Allow us to update your fitness data with your friends.</string>
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
||||||
|
<key>NSSpeechRecognitionUsageDescription</key>
|
||||||
|
<string>Solian uses speech recognition for Siri integration</string>
|
||||||
<key>NSUserActivityTypes</key>
|
<key>NSUserActivityTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>INStartCallIntent</string>
|
<string>INStartCallIntent</string>
|
||||||
@@ -109,8 +114,6 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
</array>
|
</array>
|
||||||
<key>WKCompanionAppBundleIdentifier</key>
|
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
@@ -118,5 +121,7 @@
|
|||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>WKCompanionAppBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>com.apple.developer.device-information.user-assigned-device-name</key>
|
<key>com.apple.developer.device-information.user-assigned-device-name</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.developer.healthkit</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.developer.usernotifications.communication</key>
|
<key>com.apple.developer.usernotifications.communication</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
|
|||||||
84
ios/Runner/Services/AppIntentConfiguration.swift
Normal file
84
ios/Runner/Services/AppIntentConfiguration.swift
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// AppIntentConfiguration.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct AppShortcuts: AppShortcutsProvider {
|
||||||
|
@AppShortcutsBuilder static var appShortcuts: [AppShortcut] {
|
||||||
|
AppShortcut(
|
||||||
|
intent: OpenChatIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Open chat with \(.applicationName)",
|
||||||
|
"Go to chat using \(.applicationName)",
|
||||||
|
"Show chat in \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: OpenPostIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Open post with \(.applicationName)",
|
||||||
|
"Show post using \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: OpenComposeIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Open compose with \(.applicationName)",
|
||||||
|
"New post using \(.applicationName)",
|
||||||
|
"Write post in \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: SearchContentIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Search in \(.applicationName)",
|
||||||
|
"Find content using \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: CheckNotificationsIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Check notifications with \(.applicationName)",
|
||||||
|
"Get notifications using \(.applicationName)",
|
||||||
|
"Do I have notifications in \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: SendMessageIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Send message with \(.applicationName)",
|
||||||
|
"Post message using \(.applicationName)",
|
||||||
|
"Send text using \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: ReadMessagesIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Read messages with \(.applicationName)",
|
||||||
|
"Get chat using \(.applicationName)",
|
||||||
|
"Show messages with \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: CheckUnreadChatsIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Check unread chats with \(.applicationName)",
|
||||||
|
"Do I have messages using \(.applicationName)",
|
||||||
|
"Get unread messages with \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: MarkNotificationsReadIntent(),
|
||||||
|
phrases: [
|
||||||
|
"Mark notifications read with \(.applicationName)",
|
||||||
|
"Clear notifications using \(.applicationName)",
|
||||||
|
"Mark all read with \(.applicationName)"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
296
ios/Runner/Services/AppIntentHandlers.swift
Normal file
296
ios/Runner/Services/AppIntentHandlers.swift
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
//
|
||||||
|
// AppIntentHandlers.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppIntents
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct OpenChatIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_open_chat_title"
|
||||||
|
static var description = IntentDescription("intent_open_chat_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
@Parameter(title: "Channel ID")
|
||||||
|
var channelId: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & OpensIntent {
|
||||||
|
guard let channelId = channelId, !channelId.isEmpty else {
|
||||||
|
throw AppIntentError.requiredParameter("Channel ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://chat/\(channelId)")!)
|
||||||
|
|
||||||
|
return .result(value: "Opening chat \(channelId)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct OpenPostIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_open_post_title"
|
||||||
|
static var description = IntentDescription("intent_open_post_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
@Parameter(title: "Post ID")
|
||||||
|
var postId: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & OpensIntent {
|
||||||
|
guard let postId = postId, !postId.isEmpty else {
|
||||||
|
throw AppIntentError.requiredParameter("Post ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://posts/\(postId)")!)
|
||||||
|
|
||||||
|
return .result(value: "Opening post \(postId)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct OpenComposeIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_open_compose_title"
|
||||||
|
static var description = IntentDescription("intent_open_compose_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & OpensIntent {
|
||||||
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://compose")!)
|
||||||
|
|
||||||
|
return .result(value: "Opening compose screen")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct ComposePostIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_compose_post_title"
|
||||||
|
static var description = IntentDescription("intent_compose_post_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & OpensIntent {
|
||||||
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://compose")!)
|
||||||
|
|
||||||
|
return .result(value: "Opening compose screen")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct SearchContentIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_search_title"
|
||||||
|
static var description = IntentDescription("intent_search_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
@Parameter(title: "Search Query")
|
||||||
|
var query: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & OpensIntent {
|
||||||
|
guard let query = query, !query.isEmpty else {
|
||||||
|
throw AppIntentError.requiredParameter("Search Query")
|
||||||
|
}
|
||||||
|
|
||||||
|
let encodedQuery = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? query
|
||||||
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://search?q=\(encodedQuery)")!)
|
||||||
|
|
||||||
|
return .result(value: "Searching for \"\(query)\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct ViewNotificationsIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_notifications_title"
|
||||||
|
static var description = IntentDescription("intent_notifications_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = true
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & OpensIntent {
|
||||||
|
DeepLinkHandler.shared.handle(url: URL(string: "solian://notifications")!)
|
||||||
|
|
||||||
|
return .result(value: "Opening notifications")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct CheckNotificationsIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_check_notifications_title"
|
||||||
|
static var description = IntentDescription("intent_check_notifications_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
|
do {
|
||||||
|
let count = try await NetworkService.shared.getNotificationCount()
|
||||||
|
|
||||||
|
let message: String
|
||||||
|
if count == 0 {
|
||||||
|
message = "You have no new notifications"
|
||||||
|
} else if count == 1 {
|
||||||
|
message = "You have 1 new notification"
|
||||||
|
} else {
|
||||||
|
message = "You have \(count) new notifications"
|
||||||
|
}
|
||||||
|
|
||||||
|
return .result(
|
||||||
|
value: message,
|
||||||
|
dialog: "\(message)"
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AppIntentError.networkError("Failed to check notifications: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct SendMessageIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_send_message_title"
|
||||||
|
static var description = IntentDescription("intent_send_message_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
@Parameter(title: "Channel ID")
|
||||||
|
var channelId: String?
|
||||||
|
|
||||||
|
@Parameter(title: "Message Content")
|
||||||
|
var content: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
|
guard let channelId = channelId, !channelId.isEmpty else {
|
||||||
|
throw AppIntentError.requiredParameter("Channel ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let content = content, !content.isEmpty else {
|
||||||
|
throw AppIntentError.requiredParameter("Message Content")
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try await NetworkService.shared.sendMessage(channelId: channelId, content: content)
|
||||||
|
|
||||||
|
return .result(
|
||||||
|
value: "Message sent to channel \(channelId)",
|
||||||
|
dialog: "Message sent successfully"
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AppIntentError.networkError("Failed to send message: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct ReadMessagesIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_read_messages_title"
|
||||||
|
static var description = IntentDescription("intent_read_messages_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
@Parameter(title: "Channel ID")
|
||||||
|
var channelId: String?
|
||||||
|
|
||||||
|
@Parameter(title: "Number of Messages", default: "5")
|
||||||
|
var limit: String?
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
|
guard let channelId = channelId, !channelId.isEmpty else {
|
||||||
|
throw AppIntentError.requiredParameter("Channel ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
let limitValue = Int(limit ?? "5") ?? 5
|
||||||
|
let safeLimit = max(1, min(20, limitValue))
|
||||||
|
|
||||||
|
do {
|
||||||
|
let messages = try await NetworkService.shared.getMessages(
|
||||||
|
channelId: channelId,
|
||||||
|
offset: 0,
|
||||||
|
take: safeLimit
|
||||||
|
)
|
||||||
|
|
||||||
|
if messages.isEmpty {
|
||||||
|
return .result(
|
||||||
|
value: "No messages found in channel \(channelId)",
|
||||||
|
dialog: "No messages found"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let formattedMessages = messages.compactMap { message -> String? in
|
||||||
|
let senderName = message.sender?.account?.name ?? "Unknown"
|
||||||
|
let content = message.content ?? ""
|
||||||
|
return "\(senderName): \(content)"
|
||||||
|
}.joined(separator: "\n")
|
||||||
|
|
||||||
|
return .result(
|
||||||
|
value: formattedMessages,
|
||||||
|
dialog: "Found \(messages.count) messages"
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AppIntentError.networkError("Failed to read messages: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct CheckUnreadChatsIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_unread_chats_title"
|
||||||
|
static var description = IntentDescription("intent_unread_chats_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
|
do {
|
||||||
|
let count = try await NetworkService.shared.getUnreadChatsCount()
|
||||||
|
|
||||||
|
let message: String
|
||||||
|
if count == 0 {
|
||||||
|
message = "You have no unread messages"
|
||||||
|
} else if count == 1 {
|
||||||
|
message = "You have 1 unread message"
|
||||||
|
} else {
|
||||||
|
message = "You have \(count) unread messages"
|
||||||
|
}
|
||||||
|
|
||||||
|
return .result(
|
||||||
|
value: message,
|
||||||
|
dialog: "\(message)"
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AppIntentError.networkError("Failed to check unread chats: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
struct MarkNotificationsReadIntent: AppIntent {
|
||||||
|
static var title: LocalizedStringResource = "intent_mark_read_title"
|
||||||
|
static var description = IntentDescription("intent_mark_read_desc")
|
||||||
|
static var isDiscoverable = true
|
||||||
|
static var openAppWhenRun = false
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
|
do {
|
||||||
|
try await NetworkService.shared.markNotificationsRead()
|
||||||
|
|
||||||
|
return .result(
|
||||||
|
value: "All notifications marked as read",
|
||||||
|
dialog: "All notifications marked as read"
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
throw AppIntentError.networkError("Failed to mark notifications: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AppIntentError: Error, CustomLocalizedStringResourceConvertible {
|
||||||
|
case requiredParameter(String)
|
||||||
|
case networkError(String)
|
||||||
|
|
||||||
|
var localizedStringResource: LocalizedStringResource {
|
||||||
|
switch self {
|
||||||
|
case .requiredParameter(let param):
|
||||||
|
return "\(param) is required"
|
||||||
|
case .networkError(let message):
|
||||||
|
return "Network error: \(message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
103
ios/Runner/Services/DeepLinkHandler.swift
Normal file
103
ios/Runner/Services/DeepLinkHandler.swift
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// DeepLinkHandler.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
final class DeepLinkHandler {
|
||||||
|
static let shared = DeepLinkHandler()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
|
func handle(url: URL) -> Bool {
|
||||||
|
guard url.scheme == SharedConstants.urlScheme else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let host = url.host ?? ""
|
||||||
|
let path = url.path
|
||||||
|
let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems
|
||||||
|
|
||||||
|
switch host {
|
||||||
|
case "chat":
|
||||||
|
if let channelId = url.pathComponents.count > 1 ? url.pathComponents[1] : nil {
|
||||||
|
openUrl("solian://chat/\(channelId)")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
case "posts":
|
||||||
|
if let postId = url.pathComponents.count > 1 ? url.pathComponents[1] : nil {
|
||||||
|
openUrl("solian://posts/\(postId)")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
case "search":
|
||||||
|
if let query = queryItems?.first(where: { $0.name == "query" })?.value {
|
||||||
|
let encodedQuery = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? query
|
||||||
|
openUrl("solian://search?q=\(encodedQuery)")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
case "notifications":
|
||||||
|
openUrl("solian://notifications")
|
||||||
|
return true
|
||||||
|
|
||||||
|
case "compose":
|
||||||
|
openUrl("solian://compose")
|
||||||
|
return true
|
||||||
|
|
||||||
|
default:
|
||||||
|
if path.hasPrefix("/chat/") {
|
||||||
|
let channelId = path.replacingOccurrences(of: "/chat/", with: "")
|
||||||
|
openUrl("solian://chat/\(channelId)")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if path.hasPrefix("/posts/") {
|
||||||
|
let postId = path.replacingOccurrences(of: "/posts/", with: "")
|
||||||
|
openUrl("solian://posts/\(postId)")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if path.hasPrefix("/search") {
|
||||||
|
let query = queryItems?.first(where: { $0.name == "q" })?.value ?? ""
|
||||||
|
let encodedQuery = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? query
|
||||||
|
openUrl("solian://search?q=\(encodedQuery)")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if path == "/notifications" {
|
||||||
|
openUrl("solian://notifications")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if path.hasPrefix("/compose") || path == "/compose" {
|
||||||
|
openUrl("solian://compose")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if path.hasPrefix("/dashboard") {
|
||||||
|
openUrl("solian://dashboard")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private func openUrl(_ urlString: String) {
|
||||||
|
guard let url = URL(string: urlString) else {
|
||||||
|
print("[DeepLinkHandler] Invalid URL: \(urlString)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
UIApplication.shared.open(url) { success in
|
||||||
|
if success {
|
||||||
|
print("[DeepLinkHandler] Opened URL: \(urlString)")
|
||||||
|
} else {
|
||||||
|
print("[DeepLinkHandler] Failed to open URL: \(urlString)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
177
ios/Runner/Services/NetworkService.swift
Normal file
177
ios/Runner/Services/NetworkService.swift
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
//
|
||||||
|
// NetworkService.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class NetworkService {
|
||||||
|
static let shared = NetworkService()
|
||||||
|
|
||||||
|
private let session: URLSession
|
||||||
|
private let decoder: JSONDecoder
|
||||||
|
|
||||||
|
private init() {
|
||||||
|
let config = URLSessionConfiguration.default
|
||||||
|
config.timeoutIntervalForRequest = 10
|
||||||
|
config.timeoutIntervalForResource = 30
|
||||||
|
self.session = URLSession(configuration: config)
|
||||||
|
|
||||||
|
self.decoder = JSONDecoder()
|
||||||
|
self.decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
|
}
|
||||||
|
|
||||||
|
private var baseUrl: String {
|
||||||
|
UserDefaults.shared.getServerUrl()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var authHeaders: [String: String] {
|
||||||
|
var headers = [
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
]
|
||||||
|
if let token = UserDefaults.shared.getAuthToken() {
|
||||||
|
headers["Authorization"] = "AtField \(token)"
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNotificationCount() async throws -> Int {
|
||||||
|
let url = try buildUrl(path: SharedConstants.API.notificationsCount)
|
||||||
|
let response: NotificationCountResponse = try await get(url: url)
|
||||||
|
return response.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func markNotificationsRead() async throws {
|
||||||
|
let url = try buildUrl(path: SharedConstants.API.notificationsMarkRead)
|
||||||
|
let _: EmptyResponse = try await post(url: url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUnreadChatsCount() async throws -> Int {
|
||||||
|
let url = try buildUrl(path: SharedConstants.API.unreadChats)
|
||||||
|
let response: UnreadChatsResponse = try await get(url: url)
|
||||||
|
return response.unreadCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMessages(channelId: String, offset: Int = 0, take: Int = 5) async throws -> [MessageResponse] {
|
||||||
|
let path = String(format: SharedConstants.API.messages, channelId)
|
||||||
|
let url = try buildUrl(path: path, queryItems: [
|
||||||
|
URLQueryItem(name: "offset", value: String(offset)),
|
||||||
|
URLQueryItem(name: "take", value: String(take))
|
||||||
|
])
|
||||||
|
let response: MessagesResponse = try await get(url: url)
|
||||||
|
return response.messages
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendMessage(channelId: String, content: String) async throws {
|
||||||
|
let path = String(format: SharedConstants.API.sendMessage, channelId)
|
||||||
|
let url = try buildUrl(path: path)
|
||||||
|
let body = SendMessageBody(content: content, nonce: generateNonce())
|
||||||
|
let _: EmptyResponse = try await post(url: url, body: body)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func buildUrl(path: String, queryItems: [URLQueryItem]? = nil) throws -> URL {
|
||||||
|
var components = URLComponents(string: baseUrl + path)
|
||||||
|
if let queryItems = queryItems, !queryItems.isEmpty {
|
||||||
|
components?.queryItems = queryItems
|
||||||
|
}
|
||||||
|
guard let url = components?.url else {
|
||||||
|
throw NetworkError.invalidUrl
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
private func get<T: Decodable>(url: URL) async throws -> T {
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
authHeaders.forEach { request.setValue($1, forHTTPHeaderField: $0) }
|
||||||
|
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
try validateResponse(response)
|
||||||
|
return try decoder.decode(T.self, from: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func post<T: Decodable>(url: URL) async throws -> T {
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
authHeaders.forEach { request.setValue($1, forHTTPHeaderField: $0) }
|
||||||
|
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
try validateResponse(response)
|
||||||
|
|
||||||
|
if T.self == EmptyResponse.self {
|
||||||
|
return EmptyResponse() as! T
|
||||||
|
}
|
||||||
|
|
||||||
|
return try decoder.decode(T.self, from: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func post<T: Decodable, B: Encodable>(url: URL, body: B) async throws -> T {
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
authHeaders.forEach { request.setValue($1, forHTTPHeaderField: $0) }
|
||||||
|
|
||||||
|
request.httpBody = try JSONEncoder().encode(body)
|
||||||
|
|
||||||
|
let (data, response) = try await session.data(for: request)
|
||||||
|
try validateResponse(response)
|
||||||
|
|
||||||
|
if T.self == EmptyResponse.self {
|
||||||
|
return EmptyResponse() as! T
|
||||||
|
}
|
||||||
|
|
||||||
|
return try decoder.decode(T.self, from: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func validateResponse(_ response: URLResponse) throws {
|
||||||
|
guard let httpResponse = response as? HTTPURLResponse else {
|
||||||
|
throw NetworkError.invalidResponse
|
||||||
|
}
|
||||||
|
guard (200...299).contains(httpResponse.statusCode) else {
|
||||||
|
throw NetworkError.httpError(statusCode: httpResponse.statusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func generateNonce() -> String {
|
||||||
|
"\(Date().timeIntervalSince1970)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NetworkError: Error {
|
||||||
|
case invalidUrl
|
||||||
|
case invalidResponse
|
||||||
|
case httpError(statusCode: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotificationCountResponse: Decodable {
|
||||||
|
let count: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UnreadChatsResponse: Decodable {
|
||||||
|
let unreadCount: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MessagesResponse: Decodable {
|
||||||
|
let messages: [MessageResponse]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MessageResponse: Decodable {
|
||||||
|
let content: String?
|
||||||
|
let sender: SenderResponse?
|
||||||
|
|
||||||
|
struct SenderResponse: Decodable {
|
||||||
|
let account: AccountResponse?
|
||||||
|
|
||||||
|
struct AccountResponse: Decodable {
|
||||||
|
let name: String?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SendMessageBody: Encodable {
|
||||||
|
let content: String
|
||||||
|
let nonce: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EmptyResponse: Decodable {}
|
||||||
45
ios/Runner/Services/SharedConstants.swift
Normal file
45
ios/Runner/Services/SharedConstants.swift
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// SharedConstants.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2026/1/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum SharedConstants {
|
||||||
|
static let appGroupId = "group.solsynth.solian"
|
||||||
|
static let urlScheme = "solian"
|
||||||
|
static let serverUrlKey = "flutter.app_server_url"
|
||||||
|
static let tokenKey = "flutter.dyn_user_tk"
|
||||||
|
static let defaultServerUrl = "https://api.solian.app"
|
||||||
|
|
||||||
|
enum API {
|
||||||
|
static let notificationsCount = "/ring/notifications/count"
|
||||||
|
static let notificationsMarkRead = "/ring/notifications/all/read"
|
||||||
|
static let unreadChats = "/messager/chat/unread"
|
||||||
|
static let messages = "/messager/chat/%@/messages"
|
||||||
|
static let sendMessage = "/messager/chat/%@/messages"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UserDefaults {
|
||||||
|
static let shared: UserDefaults = {
|
||||||
|
UserDefaults(suiteName: SharedConstants.appGroupId) ?? UserDefaults.standard
|
||||||
|
}()
|
||||||
|
|
||||||
|
func getServerUrl() -> String {
|
||||||
|
string(forKey: SharedConstants.serverUrlKey) ?? SharedConstants.defaultServerUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAuthToken() -> String? {
|
||||||
|
guard let jsonString = string(forKey: SharedConstants.tokenKey),
|
||||||
|
let data = jsonString.data(using: .utf8),
|
||||||
|
let jsonObject = try? JSONSerialization.jsonObject(with: data),
|
||||||
|
let jsonDict = jsonObject as? [String: Any],
|
||||||
|
let token = jsonDict["token"] as? String else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
}
|
||||||
33
ios/Runner/en.lproj/Localizable.strings
Normal file
33
ios/Runner/en.lproj/Localizable.strings
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* App Intents - Chat */
|
||||||
|
"intent_open_chat_title" = "Open Chat";
|
||||||
|
"intent_open_chat_desc" = "Open a specific chat room";
|
||||||
|
|
||||||
|
/* App Intents - Post */
|
||||||
|
"intent_open_post_title" = "Open Post";
|
||||||
|
"intent_open_post_desc" = "Open a specific post";
|
||||||
|
|
||||||
|
/* App Intents - Compose */
|
||||||
|
"intent_open_compose_title" = "Open Compose";
|
||||||
|
"intent_open_compose_desc" = "Open compose post screen";
|
||||||
|
"intent_compose_post_title" = "Compose Post";
|
||||||
|
"intent_compose_post_desc" = "Create a new post";
|
||||||
|
|
||||||
|
/* App Intents - Search */
|
||||||
|
"intent_search_title" = "Search Content";
|
||||||
|
"intent_search_desc" = "Search for content";
|
||||||
|
|
||||||
|
/* App Intents - Notifications */
|
||||||
|
"intent_notifications_title" = "View Notifications";
|
||||||
|
"intent_notifications_desc" = "View notifications";
|
||||||
|
"intent_check_notifications_title" = "Check Notifications";
|
||||||
|
"intent_check_notifications_desc" = "Check notification count";
|
||||||
|
|
||||||
|
/* App Intents - Messages */
|
||||||
|
"intent_send_message_title" = "Send Message";
|
||||||
|
"intent_send_message_desc" = "Send a message to a chat channel";
|
||||||
|
"intent_read_messages_title" = "Read Messages";
|
||||||
|
"intent_read_messages_desc" = "Read recent messages from a chat channel";
|
||||||
|
"intent_unread_chats_title" = "Check Unread Chats";
|
||||||
|
"intent_unread_chats_desc" = "Check number of unread chat messages";
|
||||||
|
"intent_mark_read_title" = "Mark Notifications Read";
|
||||||
|
"intent_mark_read_desc" = "Mark all notifications as read";
|
||||||
33
ios/Runner/es.lproj/Localizable.strings
Normal file
33
ios/Runner/es.lproj/Localizable.strings
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* App Intents - Chat */
|
||||||
|
"intent_open_chat_title" = "Abrir chat";
|
||||||
|
"intent_open_chat_desc" = "Abrir sala de chat específica";
|
||||||
|
|
||||||
|
/* App Intents - Post */
|
||||||
|
"intent_open_post_title" = "Abrir publicación";
|
||||||
|
"intent_open_post_desc" = "Abrir publicación específica";
|
||||||
|
|
||||||
|
/* App Intents - Compose */
|
||||||
|
"intent_open_compose_title" = "Abrir compose";
|
||||||
|
"intent_open_compose_desc" = "Abrir pantalla de publicación";
|
||||||
|
"intent_compose_post_title" = "Redactar publicación";
|
||||||
|
"intent_compose_post_desc" = "Crear nueva publicación";
|
||||||
|
|
||||||
|
/* App Intents - Search */
|
||||||
|
"intent_search_title" = "Buscar contenido";
|
||||||
|
"intent_search_desc" = "Buscar contenido";
|
||||||
|
|
||||||
|
/* App Intents - Notifications */
|
||||||
|
"intent_notifications_title" = "Ver notificaciones";
|
||||||
|
"intent_notifications_desc" = "Ver notificaciones";
|
||||||
|
"intent_check_notifications_title" = "Ver notificaciones";
|
||||||
|
"intent_check_notifications_desc" = "Ver número de notificaciones";
|
||||||
|
|
||||||
|
/* App Intents - Messages */
|
||||||
|
"intent_send_message_title" = "Enviar mensaje";
|
||||||
|
"intent_send_message_desc" = "Enviar mensaje a canal de chat";
|
||||||
|
"intent_read_messages_title" = "Leer mensajes";
|
||||||
|
"intent_read_messages_desc" = "Leer mensajes recientes de un canal de chat";
|
||||||
|
"intent_unread_chats_title" = "Ver chats no leídos";
|
||||||
|
"intent_unread_chats_desc" = "Ver mensajes no leídos";
|
||||||
|
"intent_mark_read_title" = "Marcar notificaciones leídas";
|
||||||
|
"intent_mark_read_desc" = "Marcar todas como leídas";
|
||||||
33
ios/Runner/ja.lproj/Localizable.strings
Normal file
33
ios/Runner/ja.lproj/Localizable.strings
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* App Intents - Chat */
|
||||||
|
"intent_open_chat_title" = "チャットを開く";
|
||||||
|
"intent_open_chat_desc" = "特定のチャットルームを開く";
|
||||||
|
|
||||||
|
/* App Intents - Post */
|
||||||
|
"intent_open_post_title" = "投稿を開く";
|
||||||
|
"intent_open_post_desc" = "特定の投稿を開く";
|
||||||
|
|
||||||
|
/* App Intents - Compose */
|
||||||
|
"intent_open_compose_title" = "作成を開く";
|
||||||
|
"intent_open_compose_desc" = "投稿作成画面を開く";
|
||||||
|
"intent_compose_post_title" = "投稿を作成する";
|
||||||
|
"intent_compose_post_desc" = "新規投稿を作成する";
|
||||||
|
|
||||||
|
/* App Intents - Search */
|
||||||
|
"intent_search_title" = "検索";
|
||||||
|
"intent_search_desc" = "コンテンツを検索";
|
||||||
|
|
||||||
|
/* App Intents - Notifications */
|
||||||
|
"intent_notifications_title" = "通知を見る";
|
||||||
|
"intent_notifications_desc" = "通知を見る";
|
||||||
|
"intent_check_notifications_title" = "通知を確認";
|
||||||
|
"intent_check_notifications_desc" = "通知数を確認";
|
||||||
|
|
||||||
|
/* App Intents - Messages */
|
||||||
|
"intent_send_message_title" = "メッセージを送信";
|
||||||
|
"intent_send_message_desc" = "チャットチャンネルにメッセージを送信";
|
||||||
|
"intent_read_messages_title" = "メッセージを読む";
|
||||||
|
"intent_read_messages_desc" = "チャットチャンネルから最近のメッセージを読む";
|
||||||
|
"intent_unread_chats_title" = "未読チャットを確認";
|
||||||
|
"intent_unread_chats_desc" = "未読チャットメッセージ数を確認";
|
||||||
|
"intent_mark_read_title" = "通知を既読にする";
|
||||||
|
"intent_mark_read_desc" = "すべての通知を既読にする";
|
||||||
33
ios/Runner/ko.lproj/Localizable.strings
Normal file
33
ios/Runner/ko.lproj/Localizable.strings
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* App Intents - Chat */
|
||||||
|
"intent_open_chat_title" = "채팅 열기";
|
||||||
|
"intent_open_chat_desc" = "특정 채팅방 열기";
|
||||||
|
|
||||||
|
/* App Intents - Post */
|
||||||
|
"intent_open_post_title" = "게시물 열기";
|
||||||
|
"intent_open_post_desc" = "특정 게시물 열기";
|
||||||
|
|
||||||
|
/* App Intents - Compose */
|
||||||
|
"intent_open_compose_title" = "글쓰기 열기";
|
||||||
|
"intent_open_compose_desc" = "글쓰기 화면 열기";
|
||||||
|
"intent_compose_post_title" = "게시물 작성";
|
||||||
|
"intent_compose_post_desc" = "새 게시물 작성";
|
||||||
|
|
||||||
|
/* App Intents - Search */
|
||||||
|
"intent_search_title" = "검색";
|
||||||
|
"intent_search_desc" = "콘텐츠 검색";
|
||||||
|
|
||||||
|
/* App Intents - Notifications */
|
||||||
|
"intent_notifications_title" = "알림 보기";
|
||||||
|
"intent_notifications_desc" = "알림 보기";
|
||||||
|
"intent_check_notifications_title" = "알림 확인";
|
||||||
|
"intent_check_notifications_desc" = "알림 수 확인";
|
||||||
|
|
||||||
|
/* App Intents - Messages */
|
||||||
|
"intent_send_message_title" = "메시지 보내기";
|
||||||
|
"intent_send_message_desc" = "채팅 채널에 메시지 보내기";
|
||||||
|
"intent_read_messages_title" = "메시지 읽기";
|
||||||
|
"intent_read_messages_desc" = "채팅 채널에서 최근 메시지 읽기";
|
||||||
|
"intent_unread_chats_title" = "읽지 않은 채팅 확인";
|
||||||
|
"intent_unread_chats_desc" = "읽지 않은 채팅 메시지 수 확인";
|
||||||
|
"intent_mark_read_title" = "알림 읽음 처리";
|
||||||
|
"intent_mark_read_desc" = "모든 알림을 읽음으로 처리";
|
||||||
33
ios/Runner/zh-Hans.lproj/Localizable.strings
Normal file
33
ios/Runner/zh-Hans.lproj/Localizable.strings
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* App Intents - Chat */
|
||||||
|
"intent_open_chat_title" = "打开聊天";
|
||||||
|
"intent_open_chat_desc" = "打开特定聊天室";
|
||||||
|
|
||||||
|
/* App Intents - Post */
|
||||||
|
"intent_open_post_title" = "打开帖子";
|
||||||
|
"intent_open_post_desc" = "打开特定帖子";
|
||||||
|
|
||||||
|
/* App Intents - Compose */
|
||||||
|
"intent_open_compose_title" = "打开撰写";
|
||||||
|
"intent_open_compose_desc" = "打开撰写帖子页面";
|
||||||
|
"intent_compose_post_title" = "撰写帖子";
|
||||||
|
"intent_compose_post_desc" = "创建新帖子";
|
||||||
|
|
||||||
|
/* App Intents - Search */
|
||||||
|
"intent_search_title" = "搜索内容";
|
||||||
|
"intent_search_desc" = "搜索内容";
|
||||||
|
|
||||||
|
/* App Intents - Notifications */
|
||||||
|
"intent_notifications_title" = "查看通知";
|
||||||
|
"intent_notifications_desc" = "查看通知";
|
||||||
|
"intent_check_notifications_title" = "检查通知";
|
||||||
|
"intent_check_notifications_desc" = "检查通知数量";
|
||||||
|
|
||||||
|
/* App Intents - Messages */
|
||||||
|
"intent_send_message_title" = "发送消息";
|
||||||
|
"intent_send_message_desc" = "发送消息到聊天频道";
|
||||||
|
"intent_read_messages_title" = "读取消息";
|
||||||
|
"intent_read_messages_desc" = "从聊天频道读取最近消息";
|
||||||
|
"intent_unread_chats_title" = "检查未读聊天";
|
||||||
|
"intent_unread_chats_desc" = "检查未读聊天消息数量";
|
||||||
|
"intent_mark_read_title" = "标记通知已读";
|
||||||
|
"intent_mark_read_desc" = "将所有通知标记为已读";
|
||||||
33
ios/Runner/zh-Hant.lproj/Localizable.strings
Normal file
33
ios/Runner/zh-Hant.lproj/Localizable.strings
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* App Intents - Chat */
|
||||||
|
"intent_open_chat_title" = "開啟聊天";
|
||||||
|
"intent_open_chat_desc" = "開啟特定聊天室";
|
||||||
|
|
||||||
|
/* App Intents - Post */
|
||||||
|
"intent_open_post_title" = "開啟貼文";
|
||||||
|
"intent_open_post_desc" = "開啟特定貼文";
|
||||||
|
|
||||||
|
/* App Intents - Compose */
|
||||||
|
"intent_open_compose_title" = "開啟撰寫";
|
||||||
|
"intent_open_compose_desc" = "開啟撰寫貼文頁面";
|
||||||
|
"intent_compose_post_title" = "撰寫貼文";
|
||||||
|
"intent_compose_post_desc" = "建立新貼文";
|
||||||
|
|
||||||
|
/* App Intents - Search */
|
||||||
|
"intent_search_title" = "搜尋內容";
|
||||||
|
"intent_search_desc" = "搜尋內容";
|
||||||
|
|
||||||
|
/* App Intents - Notifications */
|
||||||
|
"intent_notifications_title" = "查看通知";
|
||||||
|
"intent_notifications_desc" = "查看通知";
|
||||||
|
"intent_check_notifications_title" = "檢查通知";
|
||||||
|
"intent_check_notifications_desc" = "檢查通知數量";
|
||||||
|
|
||||||
|
/* App Intents - Messages */
|
||||||
|
"intent_send_message_title" = "傳送訊息";
|
||||||
|
"intent_send_message_desc" = "傳送訊息到聊天頻道";
|
||||||
|
"intent_read_messages_title" = "讀取訊息";
|
||||||
|
"intent_read_messages_desc" = "從聊天頻道讀取最近訊息";
|
||||||
|
"intent_unread_chats_title" = "檢查未讀聊天";
|
||||||
|
"intent_unread_chats_desc" = "檢查未讀聊天訊息數量";
|
||||||
|
"intent_mark_read_title" = "標記通知已讀";
|
||||||
|
"intent_mark_read_desc" = "將所有通知標記為已讀";
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/abuse_report.dart';
|
import 'package:island/accounts/accounts_models/abuse_report.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
|
|
||||||
final abuseReportServiceProvider = Provider<AbuseReportService>((ref) {
|
final abuseReportServiceProvider = Provider<AbuseReportService>((ref) {
|
||||||
return AbuseReportService(ref);
|
return AbuseReportService(ref);
|
||||||
@@ -4,11 +4,11 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/pods/paging.dart';
|
import 'package:island/pagination/pagination.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/widgets/paging/pagination_list.dart';
|
import 'package:island/shared/widgets/pagination_list.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -3,17 +3,17 @@ import 'dart:async';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_widgets/account/leveling_progress.dart';
|
||||||
import 'package:island/pods/paging.dart';
|
import 'package:island/accounts/accounts_widgets/account/stellar_program_tab.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/screens/account/credits.dart';
|
import 'package:island/pagination/pagination.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/widgets/account/leveling_progress.dart';
|
import 'package:island/accounts/account/credits.dart';
|
||||||
import 'package:island/widgets/account/stellar_program_tab.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/shared/widgets/app_scaffold.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:island/widgets/paging/pagination_list.dart';
|
import 'package:island/shared/widgets/pagination_list.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
final levelingHistoryNotifierProvider =
|
final levelingHistoryNotifierProvider =
|
||||||
@@ -6,19 +6,19 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/auth.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_devices.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/auth/auth_models/auth.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/screens/account/me/settings_auth_factors.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/screens/account/me/settings_connections.dart';
|
import 'package:island/accounts/account/me/settings_auth_factors.dart';
|
||||||
import 'package:island/screens/account/me/settings_contacts.dart';
|
import 'package:island/accounts/account/me/settings_connections.dart';
|
||||||
import 'package:island/screens/auth/captcha.dart';
|
import 'package:island/accounts/account/me/settings_contacts.dart';
|
||||||
import 'package:island/screens/auth/login.dart';
|
import 'package:island/auth/captcha.dart';
|
||||||
import 'package:island/widgets/account/account_devices.dart';
|
import 'package:island/auth/login.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/shared/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/response.dart';
|
import 'package:island/shared/widgets/response.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -7,17 +7,17 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_name.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/core/services/image.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/drive/drive_models/file.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/services/file.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/services/file_uploader.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/services/timezone.dart';
|
import 'package:island/drive/drive_service.dart';
|
||||||
import 'package:island/widgets/account/account_name.dart';
|
import 'package:island/core/services/timezone.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/shared/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -7,11 +7,11 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:flutter_otp_text_field/flutter_otp_text_field.dart';
|
import 'package:flutter_otp_text_field/flutter_otp_text_field.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/auth.dart';
|
import 'package:island/auth/auth_models/auth.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/screens/auth/login.dart';
|
import 'package:island/auth/login.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -64,8 +64,7 @@ class AuthFactorSheet extends HookConsumerWidget {
|
|||||||
if ([3].contains(factor.type)) {
|
if ([3].contains(factor.type)) {
|
||||||
final confirmed = await showDialog<bool>(
|
final confirmed = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (context) => AlertDialog(
|
||||||
(context) => AlertDialog(
|
|
||||||
title: Text('authFactorEnable').tr(),
|
title: Text('authFactorEnable').tr(),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -233,8 +232,7 @@ class AuthFactorNewSheet extends HookConsumerWidget {
|
|||||||
labelText: 'authFactor'.tr(),
|
labelText: 'authFactor'.tr(),
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
items:
|
items: kFactorTypes.entries.map((entry) {
|
||||||
kFactorTypes.entries.map((entry) {
|
|
||||||
return DropdownMenuItem<int>(
|
return DropdownMenuItem<int>(
|
||||||
value: entry.key,
|
value: entry.key,
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -261,8 +259,8 @@ class AuthFactorNewSheet extends HookConsumerWidget {
|
|||||||
hintText: 'authFactorSecretHint'.tr(),
|
hintText: 'authFactorSecretHint'.tr(),
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
onTapOutside:
|
onTapOutside: (_) =>
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
)
|
)
|
||||||
else if ([4].contains(factorType.value))
|
else if ([4].contains(factorType.value))
|
||||||
OtpTextField(
|
OtpTextField(
|
||||||
@@ -4,15 +4,15 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/auth.dart';
|
import 'package:island/auth/auth_models/auth.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/core/config.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/screens/account/me/account_settings.dart';
|
import 'package:island/accounts/account/me/account_settings.dart';
|
||||||
import 'package:island/utils/text.dart';
|
import 'package:island/core/text.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:island/widgets/response.dart';
|
import 'package:island/shared/widgets/response.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -233,14 +233,11 @@ class AccountConnectionNewSheet extends HookConsumerWidget {
|
|||||||
labelText: 'accountConnectionProvider'.tr(),
|
labelText: 'accountConnectionProvider'.tr(),
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
items:
|
items: providers.map((String provider) {
|
||||||
providers.map((String provider) {
|
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: provider,
|
value: provider,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [Text(getLocalizedProviderName(provider)).tr()],
|
||||||
Text(getLocalizedProviderName(provider)).tr(),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
@@ -296,14 +293,10 @@ class AccountConnectionsSheet extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: connections.when(
|
child: connections.when(
|
||||||
data:
|
data: (data) => RefreshIndicator(
|
||||||
(data) => RefreshIndicator(
|
onRefresh: () =>
|
||||||
onRefresh:
|
Future.sync(() => ref.invalidate(accountConnectionsProvider)),
|
||||||
() => Future.sync(
|
child: data.isEmpty
|
||||||
() => ref.invalidate(accountConnectionsProvider),
|
|
||||||
),
|
|
||||||
child:
|
|
||||||
data.isEmpty
|
|
||||||
? Center(
|
? Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'accountConnectionsEmpty'.tr(),
|
'accountConnectionsEmpty'.tr(),
|
||||||
@@ -321,13 +314,8 @@ class AccountConnectionsSheet extends HookConsumerWidget {
|
|||||||
background: Container(
|
background: Container(
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
horizontal: 20,
|
child: const Icon(Icons.delete, color: Colors.white),
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
Icons.delete,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
confirmDismiss: (direction) async {
|
confirmDismiss: (direction) async {
|
||||||
final confirm = await showConfirmAlert(
|
final confirm = await showConfirmAlert(
|
||||||
@@ -355,14 +343,10 @@ class AccountConnectionsSheet extends HookConsumerWidget {
|
|||||||
connection.provider,
|
connection.provider,
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
title:
|
title: Text(
|
||||||
Text(
|
getLocalizedProviderName(connection.provider),
|
||||||
getLocalizedProviderName(
|
|
||||||
connection.provider,
|
|
||||||
),
|
|
||||||
).tr(),
|
).tr(),
|
||||||
subtitle:
|
subtitle: connection.meta['email'] != null
|
||||||
connection.meta['email'] != null
|
|
||||||
? Text(connection.meta['email'])
|
? Text(connection.meta['email'])
|
||||||
: Text(connection.providedIdentifier),
|
: Text(connection.providedIdentifier),
|
||||||
trailing: Text(
|
trailing: Text(
|
||||||
@@ -375,10 +359,8 @@ class AccountConnectionsSheet extends HookConsumerWidget {
|
|||||||
final result = await showModalBottomSheet<bool>(
|
final result = await showModalBottomSheet<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder:
|
builder: (context) =>
|
||||||
(context) => AccountConnectionSheet(
|
AccountConnectionSheet(connection: connection),
|
||||||
connection: connection,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
if (result == true) {
|
if (result == true) {
|
||||||
ref.invalidate(accountConnectionsProvider);
|
ref.invalidate(accountConnectionsProvider);
|
||||||
@@ -389,8 +371,7 @@ class AccountConnectionsSheet extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
error:
|
error: (err, _) => ResponseErrorWidget(
|
||||||
(err, _) => ResponseErrorWidget(
|
|
||||||
error: err,
|
error: err,
|
||||||
onRetry: () => ref.invalidate(accountConnectionsProvider),
|
onRetry: () => ref.invalidate(accountConnectionsProvider),
|
||||||
),
|
),
|
||||||
@@ -3,10 +3,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -153,8 +153,7 @@ class ContactMethodSheet extends HookConsumerWidget {
|
|||||||
child: Badge(
|
child: Badge(
|
||||||
label: Text('contactMethodPrivate'.tr()),
|
label: Text('contactMethodPrivate'.tr()),
|
||||||
textColor: Theme.of(context).colorScheme.onSurface,
|
textColor: Theme.of(context).colorScheme.onSurface,
|
||||||
backgroundColor:
|
backgroundColor: Theme.of(
|
||||||
Theme.of(
|
|
||||||
context,
|
context,
|
||||||
).colorScheme.surfaceContainerHighest,
|
).colorScheme.surfaceContainerHighest,
|
||||||
),
|
),
|
||||||
@@ -319,8 +318,7 @@ class ContactMethodNewSheet extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
child:
|
child: Text(switch (contactType.value) {
|
||||||
Text(switch (contactType.value) {
|
|
||||||
0 => 'contactMethodEmailDescription',
|
0 => 'contactMethodEmailDescription',
|
||||||
1 => 'contactMethodPhoneDescription',
|
1 => 'contactMethodPhoneDescription',
|
||||||
_ => 'contactMethodAddressDescription',
|
_ => 'contactMethodAddressDescription',
|
||||||
@@ -7,33 +7,33 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/chat.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_name.dart';
|
||||||
import 'package:island/models/developer.dart';
|
import 'package:island/accounts/accounts_widgets/account/activity_presence.dart';
|
||||||
import 'package:island/models/publisher.dart';
|
import 'package:island/accounts/accounts_widgets/account/badge.dart';
|
||||||
import 'package:island/models/relationship.dart';
|
import 'package:island/accounts/accounts_widgets/account/fortune_graph.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_widgets/account/leveling_progress.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/accounts/accounts_widgets/account/status.dart';
|
||||||
import 'package:island/pods/event_calendar.dart';
|
import 'package:island/chat/chat_models/chat.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/developers/developers_models/developer.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/posts/posts_models/publisher.dart';
|
||||||
import 'package:island/services/color.dart';
|
import 'package:island/accounts/accounts_models/relationship.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/utils/text.dart';
|
import 'package:island/core/config.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/accounts/event_calendar.dart';
|
||||||
import 'package:island/services/timezone/native.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/account/account_name.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/widgets/account/activity_presence.dart';
|
import 'package:island/core/services/color.dart';
|
||||||
import 'package:island/widgets/account/badge.dart';
|
import 'package:island/core/services/responsive.dart';
|
||||||
import 'package:island/widgets/account/fortune_graph.dart';
|
import 'package:island/core/text.dart';
|
||||||
import 'package:island/widgets/account/leveling_progress.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/widgets/account/status.dart';
|
import 'package:island/core/services/timezone/native.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/shared/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:island/widgets/content/markdown.dart';
|
import 'package:island/drive/content/markdown.dart';
|
||||||
import 'package:island/widgets/safety/abuse_report_helper.dart';
|
import 'package:island/reports/reports_widgets/safety/abuse_report_helper.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:island/services/color_extraction.dart';
|
import 'package:island/core/services/color_extraction.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -6,19 +6,19 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/pods/paging.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_pfc.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_picker.dart';
|
||||||
import 'package:island/widgets/account/account_pfc.dart';
|
import 'package:island/pagination/pagination.dart';
|
||||||
import 'package:island/widgets/account/account_picker.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/shared/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:island/widgets/paging/pagination_list.dart';
|
import 'package:island/shared/widgets/pagination_list.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:relative_time/relative_time.dart';
|
import 'package:relative_time/relative_time.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:island/models/relationship.dart';
|
import 'package:island/accounts/accounts_models/relationship.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
|
|
||||||
part 'relationship.g.dart';
|
part 'relationship.g.dart';
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ class RelationshipListTile extends StatelessWidget {
|
|||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: const EdgeInsets.only(left: 16, right: 12),
|
contentPadding: const EdgeInsets.only(left: 16, right: 12),
|
||||||
leading: AccountPfcGestureDetector(
|
leading: AccountPfcRegion(
|
||||||
uname: account.name,
|
uname: account.name,
|
||||||
child: ProfilePictureWidget(file: account.profile.picture),
|
child: ProfilePictureWidget(file: account.profile.picture),
|
||||||
),
|
),
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/core/models/activity.dart';
|
||||||
import 'package:island/models/auth.dart';
|
import 'package:island/auth/auth_models/auth.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/drive/drive_models/file.dart';
|
||||||
import 'package:island/models/wallet.dart';
|
import 'package:island/wallets/wallet_models/wallet.dart';
|
||||||
|
|
||||||
part 'account.freezed.dart';
|
part 'account.freezed.dart';
|
||||||
part 'account.g.dart';
|
part 'account.g.dart';
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
|
|
||||||
part 'relationship.freezed.dart';
|
part 'relationship.freezed.dart';
|
||||||
part 'relationship.g.dart';
|
part 'relationship.g.dart';
|
||||||
@@ -2,14 +2,14 @@ import 'dart:convert';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/core/config.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/talker.dart';
|
import 'package:island/talker.dart';
|
||||||
import 'package:island/services/analytics_service.dart';
|
import 'package:island/core/services/analytics_service.dart';
|
||||||
|
|
||||||
class UserInfoNotifier extends AsyncNotifier<SnAccount?> {
|
class UserInfoNotifier extends AsyncNotifier<SnAccount?> {
|
||||||
@override
|
@override
|
||||||
@@ -3,20 +3,20 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/pods/message.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_name.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_widgets/account/activity_presence.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/accounts/accounts_widgets/account/leveling_progress.dart';
|
||||||
import 'package:island/pods/websocket.dart';
|
import 'package:island/accounts/accounts_widgets/account/status.dart';
|
||||||
import 'package:island/screens/notification.dart';
|
import 'package:island/core/websocket.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/core/database.dart';
|
||||||
import 'package:island/widgets/account/account_name.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/account/activity_presence.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/widgets/account/status.dart';
|
import 'package:island/core/services/responsive.dart';
|
||||||
import 'package:island/widgets/account/leveling_progress.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/core/debug_sheet.dart';
|
||||||
import 'package:island/widgets/debug_sheet.dart';
|
import 'package:island/notifications/notification.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -419,6 +419,13 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
context.pushNamed('reportList');
|
context.pushNamed('reportList');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'icon': Symbols.fitness_center,
|
||||||
|
'title': 'fitnessActivity',
|
||||||
|
'onTap': () {
|
||||||
|
context.pushNamed('fitnessActivity');
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
return Column(
|
return Column(
|
||||||
children: menuItems.map((item) {
|
children: menuItems.map((item) {
|
||||||
@@ -4,19 +4,19 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/core/services/responsive.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/services/udid.dart';
|
import 'package:island/core/services/udid.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:island/widgets/response.dart';
|
import 'package:island/shared/widgets/response.dart';
|
||||||
import 'package:island/widgets/sites/info_row.dart';
|
import 'package:island/shared/widgets/info_row.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
import 'package:island/shared/widgets/extended_refresh_indicator.dart';
|
||||||
|
|
||||||
part 'account_devices.g.dart';
|
part 'account_devices.g.dart';
|
||||||
|
|
||||||
@@ -26,8 +26,7 @@ Future<List<SnAuthDeviceWithSession>> authDevices(Ref ref) async {
|
|||||||
.watch(apiClientProvider)
|
.watch(apiClientProvider)
|
||||||
.get('/pass/accounts/me/devices');
|
.get('/pass/accounts/me/devices');
|
||||||
final currentId = await getUdid();
|
final currentId = await getUdid();
|
||||||
final data =
|
final data = resp.data.map<SnAuthDeviceWithSession>((e) {
|
||||||
resp.data.map<SnAuthDeviceWithSession>((e) {
|
|
||||||
final ele = SnAuthDeviceWithSession.fromJson(e);
|
final ele = SnAuthDeviceWithSession.fromJson(e);
|
||||||
return ele.copyWith(isCurrent: ele.deviceId == currentId);
|
return ele.copyWith(isCurrent: ele.deviceId == currentId);
|
||||||
}).toList();
|
}).toList();
|
||||||
@@ -91,8 +90,7 @@ class _DeviceListTile extends StatelessWidget {
|
|||||||
6 => Icons.computer, // Linux
|
6 => Icons.computer, // Linux
|
||||||
_ => Icons.device_unknown, // fallback
|
_ => Icons.device_unknown, // fallback
|
||||||
}).padding(top: 4),
|
}).padding(top: 4),
|
||||||
trailing:
|
trailing: isWideScreen(context)
|
||||||
isWideScreen(context)
|
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -216,8 +214,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
final label = await showDialog<String>(
|
final label = await showDialog<String>(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (context) => AlertDialog(
|
||||||
(context) => AlertDialog(
|
|
||||||
title: Text('authDeviceLabelTitle'.tr()),
|
title: Text('authDeviceLabelTitle'.tr()),
|
||||||
content: TextField(
|
content: TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
@@ -283,12 +280,9 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: authDevices.when(
|
child: authDevices.when(
|
||||||
data:
|
data: (data) => ExtendedRefreshIndicator(
|
||||||
(data) => ExtendedRefreshIndicator(
|
onRefresh: () =>
|
||||||
onRefresh:
|
Future.sync(() => ref.invalidate(authDevicesProvider)),
|
||||||
() => Future.sync(
|
|
||||||
() => ref.invalidate(authDevicesProvider),
|
|
||||||
),
|
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
itemCount: data.length,
|
itemCount: data.length,
|
||||||
@@ -304,8 +298,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
} else {
|
} else {
|
||||||
return Dismissible(
|
return Dismissible(
|
||||||
key: Key('device-${device.id}'),
|
key: Key('device-${device.id}'),
|
||||||
direction:
|
direction: device.isCurrent
|
||||||
device.isCurrent
|
|
||||||
? DismissDirection.startToEnd
|
? DismissDirection.startToEnd
|
||||||
: DismissDirection.horizontal,
|
: DismissDirection.horizontal,
|
||||||
background: Container(
|
background: Container(
|
||||||
@@ -333,9 +326,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
if (confirm && context.mounted) {
|
if (confirm && context.mounted) {
|
||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final apiClient = ref.watch(
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
apiClientProvider,
|
|
||||||
);
|
|
||||||
await apiClient.delete(
|
await apiClient.delete(
|
||||||
'/pass/accounts/me/devices/${device.deviceId}',
|
'/pass/accounts/me/devices/${device.deviceId}',
|
||||||
);
|
);
|
||||||
@@ -362,8 +353,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
error:
|
error: (err, _) => ResponseErrorWidget(
|
||||||
(err, _) => ResponseErrorWidget(
|
|
||||||
error: err,
|
error: err,
|
||||||
onRetry: () => ref.invalidate(authDevicesProvider),
|
onRetry: () => ref.invalidate(authDevicesProvider),
|
||||||
),
|
),
|
||||||
@@ -2,10 +2,10 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/models/wallet.dart';
|
import 'package:island/wallets/wallet_models/wallet.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:island/widgets/account/account_name.dart';
|
import 'package:island/accounts/account/profile.dart';
|
||||||
|
import 'package:island/accounts/accounts_widgets/account/account_name.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/screens/account/profile.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
@@ -7,16 +7,15 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:flutter_popup_card/flutter_popup_card.dart';
|
import 'package:flutter_popup_card/flutter_popup_card.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/screens/account/profile.dart';
|
import 'package:island/accounts/account/profile.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_name.dart';
|
||||||
import 'package:island/services/timezone/native.dart';
|
import 'package:island/accounts/accounts_widgets/account/activity_presence.dart';
|
||||||
import 'package:island/widgets/account/account_name.dart';
|
import 'package:island/accounts/accounts_widgets/account/badge.dart';
|
||||||
import 'package:island/widgets/account/activity_presence.dart';
|
import 'package:island/accounts/accounts_widgets/account/status.dart';
|
||||||
import 'package:island/widgets/account/badge.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
|
import 'package:island/core/services/timezone/native.dart';
|
||||||
import 'package:island/widgets/account/status.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/shared/widgets/response.dart';
|
||||||
import 'package:island/widgets/response.dart';
|
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -225,14 +224,10 @@ class AccountProfileCard extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountPfcGestureDetector extends StatelessWidget {
|
class AccountPfcRegion extends StatelessWidget {
|
||||||
final String? uname;
|
final String? uname;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const AccountPfcGestureDetector({
|
const AccountPfcRegion({super.key, required this.uname, required this.child});
|
||||||
super.key,
|
|
||||||
required this.uname,
|
|
||||||
required this.child,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -4,9 +4,9 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'account_picker.g.dart';
|
part 'account_picker.g.dart';
|
||||||
618
lib/accounts/accounts_widgets/account/activity_presence.dart
Normal file
618
lib/accounts/accounts_widgets/account/activity_presence.dart
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/core/models/activity.dart';
|
||||||
|
import 'package:island/activity/activity_rpc.dart';
|
||||||
|
import 'package:island/drive/content/image.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
|
part 'activity_presence.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<Map<String, String>?> discordAssets(
|
||||||
|
Ref ref,
|
||||||
|
SnPresenceActivity activity,
|
||||||
|
) async {
|
||||||
|
final hasDiscordSmall =
|
||||||
|
activity.smallImage != null &&
|
||||||
|
activity.smallImage!.startsWith('discord:');
|
||||||
|
final hasDiscordLarge =
|
||||||
|
activity.largeImage != null &&
|
||||||
|
activity.largeImage!.startsWith('discord:');
|
||||||
|
|
||||||
|
if (hasDiscordSmall || hasDiscordLarge) {
|
||||||
|
final dio = Dio();
|
||||||
|
final response = await dio.get(
|
||||||
|
'https://discordapp.com/api/oauth2/applications/${activity.manualId}/assets',
|
||||||
|
);
|
||||||
|
final data = response.data as List<dynamic>;
|
||||||
|
return {
|
||||||
|
for (final item in data) item['name'] as String: item['id'] as String,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<String?> discordAssetsUrl(
|
||||||
|
Ref ref,
|
||||||
|
SnPresenceActivity activity,
|
||||||
|
String key,
|
||||||
|
) async {
|
||||||
|
final assets = await ref.watch(discordAssetsProvider(activity).future);
|
||||||
|
if (assets != null && assets.containsKey(key)) {
|
||||||
|
final assetId = assets[key]!;
|
||||||
|
return 'https://cdn.discordapp.com/app-assets/${activity.manualId}/$assetId.png';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kPresenceActivityTypes = [
|
||||||
|
'unknown',
|
||||||
|
'presenceTypeGaming',
|
||||||
|
'presenceTypeMusic',
|
||||||
|
'presenceTypeWorkout',
|
||||||
|
];
|
||||||
|
|
||||||
|
const kPresenceActivityIcons = <IconData>[
|
||||||
|
Symbols.question_mark_rounded,
|
||||||
|
Symbols.play_arrow_rounded,
|
||||||
|
Symbols.music_note_rounded,
|
||||||
|
Symbols.running_with_errors,
|
||||||
|
];
|
||||||
|
|
||||||
|
class ActivityPresenceWidget extends StatefulWidget {
|
||||||
|
final String uname;
|
||||||
|
final bool isCompact;
|
||||||
|
final EdgeInsets compactPadding;
|
||||||
|
|
||||||
|
const ActivityPresenceWidget({
|
||||||
|
super.key,
|
||||||
|
required this.uname,
|
||||||
|
this.isCompact = false,
|
||||||
|
this.compactPadding = EdgeInsets.zero,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ActivityPresenceWidget> createState() => _ActivityPresenceWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
late AnimationController _progressController;
|
||||||
|
late Animation<double> _progressAnimation;
|
||||||
|
double _startProgress = 0.0;
|
||||||
|
double _endProgress = 0.0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_progressController = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: const Duration(seconds: 1),
|
||||||
|
);
|
||||||
|
_progressAnimation = Tween<double>(
|
||||||
|
begin: 0.0,
|
||||||
|
end: 0.0,
|
||||||
|
).animate(_progressController);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_progressController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _buildImages(WidgetRef ref, SnPresenceActivity activity) {
|
||||||
|
final List<Widget> images = [];
|
||||||
|
|
||||||
|
if (activity.largeImage != null) {
|
||||||
|
if (activity.largeImage!.startsWith('discord:')) {
|
||||||
|
final key = activity.largeImage!.substring('discord:'.length);
|
||||||
|
final urlAsync = ref.watch(discordAssetsUrlProvider(activity, key));
|
||||||
|
images.add(
|
||||||
|
urlAsync.when(
|
||||||
|
data: (url) => url != null
|
||||||
|
? ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
imageUrl: url,
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
loading: () => const SizedBox(
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
|
),
|
||||||
|
error: (error, stack) => const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
images.add(
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: UniversalImage(
|
||||||
|
uri: activity.largeImage!,
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activity.smallImage != null) {
|
||||||
|
if (activity.smallImage!.startsWith('discord:')) {
|
||||||
|
final key = activity.smallImage!.substring('discord:'.length);
|
||||||
|
final urlAsync = ref.watch(discordAssetsUrlProvider(activity, key));
|
||||||
|
images.add(
|
||||||
|
urlAsync.when(
|
||||||
|
data: (url) => url != null
|
||||||
|
? ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
imageUrl: url,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
loading: () => const SizedBox(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
|
),
|
||||||
|
error: (error, stack) => const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
images.add(
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: UniversalImage(
|
||||||
|
uri: activity.smallImage!,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer(
|
||||||
|
builder: (BuildContext context, WidgetRef ref, Widget? child) {
|
||||||
|
final activitiesAsync = ref.watch(
|
||||||
|
presenceActivitiesProvider(widget.uname),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (widget.isCompact) {
|
||||||
|
return activitiesAsync.when(
|
||||||
|
data: (activities) {
|
||||||
|
if (activities.isEmpty) return const SizedBox.shrink();
|
||||||
|
final activity = activities.first;
|
||||||
|
return Padding(
|
||||||
|
padding: widget.compactPadding,
|
||||||
|
child: Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
if (activity.largeImage != null)
|
||||||
|
activity.largeImage!.startsWith('discord:')
|
||||||
|
? ref
|
||||||
|
.watch(
|
||||||
|
discordAssetsUrlProvider(
|
||||||
|
activity,
|
||||||
|
activity.largeImage!.substring(
|
||||||
|
'discord:'.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.when(
|
||||||
|
data: (url) => url != null
|
||||||
|
? ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
imageUrl: url,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
loading: () => const SizedBox(
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
error: (error, stack) =>
|
||||||
|
const SizedBox.shrink(),
|
||||||
|
)
|
||||||
|
: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
child: UniversalImage(
|
||||||
|
uri: activity.largeImage!,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
(activity.title?.isEmpty ?? true)
|
||||||
|
? 'unknown'.tr()
|
||||||
|
: activity.title!,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
).fontSize(13),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
kPresenceActivityTypes[activity.type],
|
||||||
|
).tr().fontSize(11),
|
||||||
|
Icon(
|
||||||
|
kPresenceActivityIcons[activity.type],
|
||||||
|
size: 15,
|
||||||
|
fill: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
StreamBuilder(
|
||||||
|
stream: Stream.periodic(const Duration(seconds: 1)),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
|
||||||
|
if (activity.manualId == 'spotify' &&
|
||||||
|
activity.meta != null) {
|
||||||
|
final meta = activity.meta as Map<String, dynamic>;
|
||||||
|
final progressMs = meta['progress_ms'] as int? ?? 0;
|
||||||
|
final durationMs =
|
||||||
|
meta['track_duration_ms'] as int? ?? 1;
|
||||||
|
final elapsed = now
|
||||||
|
.difference(activity.createdAt)
|
||||||
|
.inMilliseconds;
|
||||||
|
final currentProgressMs =
|
||||||
|
(progressMs + elapsed) % durationMs;
|
||||||
|
final progressValue = currentProgressMs / durationMs;
|
||||||
|
if (progressValue != _endProgress) {
|
||||||
|
_startProgress = _endProgress;
|
||||||
|
_endProgress = progressValue;
|
||||||
|
_progressAnimation = Tween<double>(
|
||||||
|
begin: _startProgress,
|
||||||
|
end: _endProgress,
|
||||||
|
).animate(_progressController);
|
||||||
|
_progressController.forward(from: 0.0);
|
||||||
|
}
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: _progressAnimation,
|
||||||
|
builder: (context, child) {
|
||||||
|
final animatedValue = _progressAnimation.value;
|
||||||
|
final animatedProgressMs =
|
||||||
|
(animatedValue * durationMs).toInt();
|
||||||
|
final currentMin = animatedProgressMs ~/ 60000;
|
||||||
|
final currentSec =
|
||||||
|
(animatedProgressMs % 60000) ~/ 1000;
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
spacing: 2,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${currentMin.toString().padLeft(2, '0')}:${currentSec.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 120,
|
||||||
|
child: LinearProgressIndicator(
|
||||||
|
value: animatedValue,
|
||||||
|
backgroundColor: Colors.grey.shade300,
|
||||||
|
stopIndicatorColor: Colors.green,
|
||||||
|
trackGap: 0,
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
|
Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).padding(top: 2),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final duration = now.difference(activity.createdAt);
|
||||||
|
final hours = duration.inHours.toString().padLeft(
|
||||||
|
2,
|
||||||
|
'0',
|
||||||
|
);
|
||||||
|
final minutes = (duration.inMinutes % 60)
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0');
|
||||||
|
final seconds = (duration.inSeconds % 60)
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0');
|
||||||
|
return Text(
|
||||||
|
'$hours:$minutes:$seconds',
|
||||||
|
).textColor(Colors.green).fontSize(12);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const SizedBox.shrink(),
|
||||||
|
error: (error, stack) => const SizedBox.shrink(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return activitiesAsync.when(
|
||||||
|
data: (activities) => Card(
|
||||||
|
margin: EdgeInsets.zero,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'activities',
|
||||||
|
).tr().bold().padding(horizontal: 16, vertical: 4),
|
||||||
|
if (activities.isEmpty)
|
||||||
|
Row(
|
||||||
|
spacing: 4,
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.inbox, size: 16),
|
||||||
|
Text('dataEmpty').tr().fontSize(13),
|
||||||
|
],
|
||||||
|
).opacity(0.75).padding(horizontal: 16, bottom: 8),
|
||||||
|
...activities.map((activity) {
|
||||||
|
final images = _buildImages(ref, activity);
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: BorderSide(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
margin: EdgeInsets.zero,
|
||||||
|
child: ListTile(
|
||||||
|
title: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (images.isNotEmpty)
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
spacing: 8,
|
||||||
|
children: images,
|
||||||
|
).padding(vertical: 4),
|
||||||
|
Row(
|
||||||
|
spacing: 2,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
(activity.title?.isEmpty ?? true)
|
||||||
|
? 'unknown'.tr()
|
||||||
|
: activity.title!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (activity.titleUrl != null &&
|
||||||
|
activity.titleUrl!.isNotEmpty)
|
||||||
|
IconButton(
|
||||||
|
visualDensity: const VisualDensity(
|
||||||
|
vertical: -4,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
launchUrlString(activity.titleUrl!);
|
||||||
|
},
|
||||||
|
icon: const Icon(Symbols.launch_rounded),
|
||||||
|
iconSize: 16,
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 28,
|
||||||
|
maxHeight: 28,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
subtitle: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
spacing: 4,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
kPresenceActivityTypes[activity.type],
|
||||||
|
).tr(),
|
||||||
|
Icon(
|
||||||
|
kPresenceActivityIcons[activity.type],
|
||||||
|
size: 16,
|
||||||
|
fill: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (activity.manualId == 'spotify' &&
|
||||||
|
activity.meta != null)
|
||||||
|
StreamBuilder(
|
||||||
|
stream: Stream.periodic(
|
||||||
|
const Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final meta =
|
||||||
|
activity.meta as Map<String, dynamic>;
|
||||||
|
final progressMs =
|
||||||
|
meta['progress_ms'] as int? ?? 0;
|
||||||
|
final durationMs =
|
||||||
|
meta['track_duration_ms'] as int? ?? 1;
|
||||||
|
final elapsed = now
|
||||||
|
.difference(activity.createdAt)
|
||||||
|
.inMilliseconds;
|
||||||
|
final currentProgressMs =
|
||||||
|
(progressMs + elapsed) % durationMs;
|
||||||
|
final progressValue =
|
||||||
|
currentProgressMs / durationMs;
|
||||||
|
if (progressValue != _endProgress) {
|
||||||
|
_startProgress = _endProgress;
|
||||||
|
_endProgress = progressValue;
|
||||||
|
_progressAnimation = Tween<double>(
|
||||||
|
begin: _startProgress,
|
||||||
|
end: _endProgress,
|
||||||
|
).animate(_progressController);
|
||||||
|
_progressController.forward(from: 0.0);
|
||||||
|
}
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: _progressAnimation,
|
||||||
|
builder: (context, child) {
|
||||||
|
final animatedValue =
|
||||||
|
_progressAnimation.value;
|
||||||
|
final animatedProgressMs =
|
||||||
|
(animatedValue * durationMs)
|
||||||
|
.toInt();
|
||||||
|
final currentMin =
|
||||||
|
animatedProgressMs ~/ 60000;
|
||||||
|
final currentSec =
|
||||||
|
(animatedProgressMs % 60000) ~/
|
||||||
|
1000;
|
||||||
|
final totalMin = durationMs ~/ 60000;
|
||||||
|
final totalSec =
|
||||||
|
(durationMs % 60000) ~/ 1000;
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
spacing: 4,
|
||||||
|
children: [
|
||||||
|
LinearProgressIndicator(
|
||||||
|
value: animatedValue,
|
||||||
|
backgroundColor:
|
||||||
|
Colors.grey.shade300,
|
||||||
|
trackGap: 0,
|
||||||
|
stopIndicatorColor: Colors.green,
|
||||||
|
valueColor:
|
||||||
|
AlwaysStoppedAnimation<Color>(
|
||||||
|
Colors.green,
|
||||||
|
),
|
||||||
|
).padding(top: 3),
|
||||||
|
Text(
|
||||||
|
'${currentMin.toString().padLeft(2, '0')}:${currentSec.toString().padLeft(2, '0')} / ${totalMin.toString().padLeft(2, '0')}:${totalSec.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else
|
||||||
|
StreamBuilder(
|
||||||
|
stream: Stream.periodic(
|
||||||
|
const Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
|
||||||
|
final duration = now.difference(
|
||||||
|
activity.createdAt,
|
||||||
|
);
|
||||||
|
final hours = duration.inHours
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0');
|
||||||
|
final minutes = (duration.inMinutes % 60)
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0');
|
||||||
|
final seconds = (duration.inSeconds % 60)
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0');
|
||||||
|
return Text(
|
||||||
|
'$hours:$minutes:$seconds',
|
||||||
|
).textColor(Colors.green);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (activity.subtitle?.isNotEmpty ?? false)
|
||||||
|
Row(
|
||||||
|
spacing: 2,
|
||||||
|
children: [
|
||||||
|
Flexible(child: Text(activity.subtitle!)),
|
||||||
|
if (activity.titleUrl != null &&
|
||||||
|
activity.titleUrl!.isNotEmpty)
|
||||||
|
IconButton(
|
||||||
|
visualDensity: const VisualDensity(
|
||||||
|
vertical: -4,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
launchUrlString(activity.titleUrl!);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Symbols.launch_rounded,
|
||||||
|
),
|
||||||
|
iconSize: 16,
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 28,
|
||||||
|
maxHeight: 28,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (activity.caption?.isNotEmpty ?? false)
|
||||||
|
Text(activity.caption!),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).padding(horizontal: 8),
|
||||||
|
if (activity.manualId == 'spotify')
|
||||||
|
Positioned(
|
||||||
|
top: 16,
|
||||||
|
right: 24,
|
||||||
|
child: Tooltip(
|
||||||
|
message: 'Listening on Spotify',
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/oidc/spotify.png',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 8, top: 8, bottom: 16),
|
||||||
|
),
|
||||||
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
error: (error, stack) =>
|
||||||
|
Center(child: Text('Error loading activities: $error')),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/models/badge.dart';
|
import 'package:island/accounts/accounts_models/badge.dart';
|
||||||
|
|
||||||
class BadgeList extends StatelessWidget {
|
class BadgeList extends StatelessWidget {
|
||||||
final List<SnAccountBadge> badges;
|
final List<SnAccountBadge> badges;
|
||||||
@@ -2,11 +2,11 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/accounts/accounts_widgets/account/event_details_widget.dart';
|
||||||
|
import 'package:island/core/models/activity.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:island/widgets/account/event_details_widget.dart';
|
|
||||||
import 'package:table_calendar/table_calendar.dart';
|
import 'package:table_calendar/table_calendar.dart';
|
||||||
|
|
||||||
/// A reusable widget for displaying an event calendar with event details
|
/// A reusable widget for displaying an event calendar with event details
|
||||||
@@ -89,12 +89,12 @@ class EventCalendarWidget extends HookConsumerWidget {
|
|||||||
return Center(child: Text(text));
|
return Center(child: Text(text));
|
||||||
},
|
},
|
||||||
markerBuilder: (context, day, events) {
|
markerBuilder: (context, day, events) {
|
||||||
final checkInResult =
|
final checkInResult = events
|
||||||
events.whereType<SnCheckInResult>().firstOrNull;
|
.whereType<SnCheckInResult>()
|
||||||
|
.firstOrNull;
|
||||||
final statuses = events.whereType<SnAccountStatus>().toList();
|
final statuses = events.whereType<SnAccountStatus>().toList();
|
||||||
|
|
||||||
final textColor =
|
final textColor = isSameDay(selectedDay.value, day)
|
||||||
isSameDay(selectedDay.value, day)
|
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: isSameDay(DateTime.now(), day)
|
: isSameDay(DateTime.now(), day)
|
||||||
? Colors.white
|
? Colors.white
|
||||||
@@ -152,8 +152,7 @@ class EventCalendarWidget extends HookConsumerWidget {
|
|||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final event =
|
final event = events.value
|
||||||
events.value
|
|
||||||
?.where((e) => isSameDay(e.date, selectedDay.value))
|
?.where((e) => isSameDay(e.date, selectedDay.value))
|
||||||
.firstOrNull;
|
.firstOrNull;
|
||||||
return EventDetailsWidget(
|
return EventDetailsWidget(
|
||||||
@@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/pods/event_calendar.dart';
|
import 'package:island/accounts/account/profile.dart';
|
||||||
import 'package:island/screens/account/profile.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_nameplate.dart';
|
||||||
import 'package:island/widgets/account/account_nameplate.dart';
|
import 'package:island/accounts/accounts_widgets/account/event_calendar.dart';
|
||||||
import 'package:island/widgets/account/event_calendar.dart';
|
import 'package:island/accounts/accounts_widgets/account/fortune_graph.dart';
|
||||||
import 'package:island/widgets/account/fortune_graph.dart';
|
import 'package:island/accounts/event_calendar.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
/// A reusable content widget for event calendar that can be used in screens or sheets
|
/// A reusable content widget for event calendar that can be used in screens or sheets
|
||||||
@@ -85,8 +85,7 @@ class EventCalendarContent extends HookConsumerWidget {
|
|||||||
} else {
|
} else {
|
||||||
// Screen layout - with responsive design
|
// Screen layout - with responsive design
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child:
|
child: MediaQuery.of(context).size.width > 480
|
||||||
MediaQuery.of(context).size.width > 480
|
|
||||||
? ConstrainedBox(
|
? ConstrainedBox(
|
||||||
constraints: BoxConstraints(maxWidth: 480),
|
constraints: BoxConstraints(maxWidth: 480),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/core/models/activity.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/utils/activity_utils.dart';
|
import 'package:island/activity/activity_utils.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -2,9 +2,9 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/accounts/accounts_widgets/account/event_calendar_content.dart';
|
||||||
import 'package:island/widgets/account/event_calendar_content.dart';
|
import 'package:island/core/models/activity.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
/// A widget that displays a graph of fortune levels over time
|
/// A widget that displays a graph of fortune levels over time
|
||||||
@@ -73,8 +73,7 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder:
|
builder: (context) => SheetScaffold(
|
||||||
(context) => SheetScaffold(
|
|
||||||
titleText: 'eventCalendar'.tr(),
|
titleText: 'eventCalendar'.tr(),
|
||||||
child: EventCalendarContent(
|
child: EventCalendarContent(
|
||||||
name: eventCalandarUser!,
|
name: eventCalandarUser!,
|
||||||
@@ -95,8 +94,7 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create spots for the line chart
|
// Create spots for the line chart
|
||||||
final spots =
|
final spots = data
|
||||||
data
|
|
||||||
.map(
|
.map(
|
||||||
(e) => FlSpot(
|
(e) => FlSpot(
|
||||||
e.date.millisecondsSinceEpoch.toDouble(),
|
e.date.millisecondsSinceEpoch.toDouble(),
|
||||||
@@ -194,8 +192,9 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'checkInResultLevel$level'.tr(),
|
text: 'checkInResultLevel$level'.tr(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color:
|
color: Theme.of(
|
||||||
Theme.of(context).colorScheme.onSurface,
|
context,
|
||||||
|
).colorScheme.onSurface,
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -204,10 +203,8 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
}).toList();
|
}).toList();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
touchCallback: (
|
touchCallback:
|
||||||
FlTouchEvent event,
|
(FlTouchEvent event, LineTouchResponse? response) {
|
||||||
LineTouchResponse? response,
|
|
||||||
) {
|
|
||||||
if (event is FlTapUpEvent &&
|
if (event is FlTapUpEvent &&
|
||||||
response != null &&
|
response != null &&
|
||||||
response.lineBarSpots != null &&
|
response.lineBarSpots != null &&
|
||||||
@@ -234,8 +231,9 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
radius: 4,
|
radius: 4,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
strokeColor:
|
strokeColor: Theme.of(
|
||||||
Theme.of(context).colorScheme.surface,
|
context,
|
||||||
|
).colorScheme.surface,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -4,10 +4,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_pfc.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/account/account_pfc.dart';
|
import 'package:island/core/config.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -101,7 +101,7 @@ class FriendsOverviewWidget extends HookConsumerWidget {
|
|||||||
itemCount: onlineFriends.length,
|
itemCount: onlineFriends.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final friend = onlineFriends[index];
|
final friend = onlineFriends[index];
|
||||||
return AccountPfcGestureDetector(
|
return AccountPfcRegion(
|
||||||
uname: friend.account.name,
|
uname: friend.account.name,
|
||||||
child: _FriendTile(friend: friend),
|
child: _FriendTile(friend: friend),
|
||||||
);
|
);
|
||||||
@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/screens/account/me/settings_connections.dart';
|
import 'package:island/accounts/account/me/settings_connections.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class RestorePurchaseSheet extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
await client.post(
|
await client.post(
|
||||||
'/pass/subscriptions/order/restore/${selectedProvider.value!}',
|
'/wallet/subscriptions/order/restore/${selectedProvider.value!}',
|
||||||
data: {'order_id': orderIdController.text.trim()},
|
data: {'order_id': orderIdController.text.trim()},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -79,8 +79,7 @@ class RestorePurchaseSheet extends HookConsumerWidget {
|
|||||||
hint: Text('selectProvider'.tr()),
|
hint: Text('selectProvider'.tr()),
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
items:
|
items: providers.map((provider) {
|
||||||
providers.map((provider) {
|
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: provider,
|
value: provider,
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -122,8 +121,7 @@ class RestorePurchaseSheet extends HookConsumerWidget {
|
|||||||
// Restore Button
|
// Restore Button
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: isLoading.value ? null : restorePurchase,
|
onPressed: isLoading.value ? null : restorePurchase,
|
||||||
child:
|
child: isLoading.value
|
||||||
isLoading.value
|
|
||||||
? const SizedBox(
|
? const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
width: 20,
|
width: 20,
|
||||||
@@ -2,13 +2,13 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/account/profile.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/accounts/accounts_widgets/account/status_creation.dart';
|
||||||
import 'package:island/screens/account/profile.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/utils/activity_utils.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/widgets/account/status_creation.dart';
|
import 'package:island/activity/activity_utils.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -78,9 +78,7 @@ class AccountStatusCreationWidget extends HookConsumerWidget {
|
|||||||
return InkWell(
|
return InkWell(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: userStatus.when(
|
child: userStatus.when(
|
||||||
data:
|
data: (status) => (status?.isCustomized ?? false)
|
||||||
(status) =>
|
|
||||||
(status?.isCustomized ?? false)
|
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.only(left: 4),
|
padding: const EdgeInsets.only(left: 4),
|
||||||
child: AccountStatusWidget(
|
child: AccountStatusWidget(
|
||||||
@@ -108,8 +106,7 @@ class AccountStatusCreationWidget extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
).opacity(0.85),
|
).opacity(0.85),
|
||||||
error:
|
error: (error, _) => Padding(
|
||||||
(error, _) => Padding(
|
|
||||||
padding:
|
padding:
|
||||||
padding ?? EdgeInsets.symmetric(horizontal: 26, vertical: 12),
|
padding ?? EdgeInsets.symmetric(horizontal: 26, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -117,8 +114,7 @@ class AccountStatusCreationWidget extends HookConsumerWidget {
|
|||||||
children: [Icon(Symbols.close), Text('Error: $error')],
|
children: [Icon(Symbols.close), Text('Error: $error')],
|
||||||
),
|
),
|
||||||
).opacity(0.85),
|
).opacity(0.85),
|
||||||
loading:
|
loading: () => Padding(
|
||||||
() => Padding(
|
|
||||||
padding:
|
padding:
|
||||||
padding ?? EdgeInsets.symmetric(horizontal: 26, vertical: 12),
|
padding ?? EdgeInsets.symmetric(horizontal: 26, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -132,10 +128,8 @@ class AccountStatusCreationWidget extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
builder:
|
builder: (context) => AccountStatusCreationSheet(
|
||||||
(context) => AccountStatusCreationSheet(
|
initialStatus: (userStatus.value?.isCustomized ?? false)
|
||||||
initialStatus:
|
|
||||||
(userStatus.value?.isCustomized ?? false)
|
|
||||||
? userStatus.value
|
? userStatus.value
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
@@ -187,8 +181,7 @@ class AccountStatusWidget extends HookConsumerWidget {
|
|||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (context) => AlertDialog(
|
||||||
(context) => AlertDialog(
|
|
||||||
title: Text('Activity Details'),
|
title: Text('Activity Details'),
|
||||||
content: buildActivityDetails(status.value),
|
content: buildActivityDetails(status.value),
|
||||||
actions: [
|
actions: [
|
||||||
@@ -213,8 +206,7 @@ class AccountStatusWidget extends HookConsumerWidget {
|
|||||||
)
|
)
|
||||||
else
|
else
|
||||||
Flexible(
|
Flexible(
|
||||||
child:
|
child: Text(
|
||||||
Text(
|
|
||||||
(status.value?.label ?? 'offline').toLowerCase(),
|
(status.value?.label ?? 'offline').toLowerCase(),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
@@ -4,12 +4,12 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_widgets/account/status.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/account/status.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
|
||||||
class AccountStatusCreationSheet extends HookConsumerWidget {
|
class AccountStatusCreationSheet extends HookConsumerWidget {
|
||||||
@@ -74,12 +74,12 @@ class AccountStatusCreationSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
return SheetScaffold(
|
return SheetScaffold(
|
||||||
heightFactor: 0.6,
|
heightFactor: 0.6,
|
||||||
titleText:
|
titleText: initialStatus == null
|
||||||
initialStatus == null ? 'statusCreate'.tr() : 'statusUpdate'.tr(),
|
? 'statusCreate'.tr()
|
||||||
|
: 'statusUpdate'.tr(),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed:
|
onPressed: submitting.value
|
||||||
submitting.value
|
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
submitStatus();
|
submitStatus();
|
||||||
@@ -116,8 +116,8 @@ class AccountStatusCreationSheet extends HookConsumerWidget {
|
|||||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTapOutside:
|
onTapOutside: (_) =>
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Text(
|
Text(
|
||||||
@@ -7,18 +7,18 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
import 'package:island/models/wallet.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_pfc.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_widgets/account/account_picker.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/accounts/accounts_widgets/account/restore_purchase_sheet.dart';
|
||||||
import 'package:island/services/time.dart';
|
import 'package:island/wallets/wallet_models/wallet.dart';
|
||||||
import 'package:island/widgets/account/account_pfc.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/widgets/account/account_picker.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/widgets/account/restore_purchase_sheet.dart';
|
import 'package:island/core/services/time.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:island/widgets/payment/payment_overlay.dart';
|
import 'package:island/payment/payment_overlay.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
@@ -30,7 +30,7 @@ part 'stellar_program_tab.g.dart';
|
|||||||
Future<SnWalletSubscription?> accountStellarSubscription(Ref ref) async {
|
Future<SnWalletSubscription?> accountStellarSubscription(Ref ref) async {
|
||||||
try {
|
try {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/pass/subscriptions/fuzzy/solian.stellar');
|
final resp = await client.get('/wallet/subscriptions/fuzzy/solian.stellar');
|
||||||
return SnWalletSubscription.fromJson(resp.data);
|
return SnWalletSubscription.fromJson(resp.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is DioException && err.response?.statusCode == 404) return null;
|
if (err is DioException && err.response?.statusCode == 404) return null;
|
||||||
@@ -46,7 +46,7 @@ Future<List<SnWalletGift>> accountSentGifts(
|
|||||||
}) async {
|
}) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get(
|
final resp = await client.get(
|
||||||
'/pass/subscriptions/gifts/sent?offset=$offset&take=$take',
|
'/wallet/subscriptions/gifts/sent?offset=$offset&take=$take',
|
||||||
);
|
);
|
||||||
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ Future<List<SnWalletGift>> accountReceivedGifts(
|
|||||||
}) async {
|
}) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get(
|
final resp = await client.get(
|
||||||
'/pass/subscriptions/gifts/received?offset=$offset&take=$take',
|
'/wallet/subscriptions/gifts/received?offset=$offset&take=$take',
|
||||||
);
|
);
|
||||||
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
return (resp.data as List).map((e) => SnWalletGift.fromJson(e)).toList();
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ Future<List<SnWalletGift>> accountReceivedGifts(
|
|||||||
@riverpod
|
@riverpod
|
||||||
Future<SnWalletGift> accountGift(Ref ref, String giftId) async {
|
Future<SnWalletGift> accountGift(Ref ref, String giftId) async {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/pass/subscriptions/gifts/$giftId');
|
final resp = await client.get('/wallet/subscriptions/gifts/$giftId');
|
||||||
return SnWalletGift.fromJson(resp.data);
|
return SnWalletGift.fromJson(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,8 +120,7 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
|
|||||||
).colorScheme.outline.withOpacity(0.2),
|
).colorScheme.outline.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child:
|
child: selectedRecipient != null
|
||||||
selectedRecipient != null
|
|
||||||
? ListTile(
|
? ListTile(
|
||||||
contentPadding: const EdgeInsets.only(
|
contentPadding: const EdgeInsets.only(
|
||||||
left: 20,
|
left: 20,
|
||||||
@@ -139,20 +138,16 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
|
|||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'selectedRecipient'.tr(),
|
'selectedRecipient'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodySmall
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodySmall?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
|
||||||
Theme.of(
|
|
||||||
context,
|
context,
|
||||||
).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
onPressed:
|
onPressed: () =>
|
||||||
() => setState(
|
setState(() => selectedRecipient = null),
|
||||||
() => selectedRecipient = null,
|
|
||||||
),
|
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.clear,
|
Icons.clear,
|
||||||
color: Theme.of(context).colorScheme.error,
|
color: Theme.of(context).colorScheme.error,
|
||||||
@@ -166,19 +161,16 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
|
|||||||
Icon(
|
Icon(
|
||||||
Icons.person_add_outlined,
|
Icons.person_add_outlined,
|
||||||
size: 48,
|
size: 48,
|
||||||
color:
|
color: Theme.of(
|
||||||
Theme.of(
|
|
||||||
context,
|
context,
|
||||||
).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text(
|
Text(
|
||||||
'noRecipientSelected'.tr(),
|
'noRecipientSelected'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodyMedium
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodyMedium?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
|
||||||
Theme.of(
|
|
||||||
context,
|
context,
|
||||||
).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
@@ -186,11 +178,9 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
|
|||||||
const Gap(4),
|
const Gap(4),
|
||||||
Text(
|
Text(
|
||||||
'thisWillBeAnOpenGift'.tr(),
|
'thisWillBeAnOpenGift'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodySmall
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodySmall?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
|
||||||
Theme.of(
|
|
||||||
context,
|
context,
|
||||||
).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
@@ -259,8 +249,8 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
onTapOutside:
|
onTapOutside: (_) =>
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -274,11 +264,10 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
onPressed:
|
onPressed: () =>
|
||||||
() => Navigator.of(context).pop(<String, dynamic>{
|
Navigator.of(context).pop(<String, dynamic>{
|
||||||
'recipient': null,
|
'recipient': null,
|
||||||
'message':
|
'message': messageController.text.trim().isEmpty
|
||||||
messageController.text.trim().isEmpty
|
|
||||||
? null
|
? null
|
||||||
: messageController.text.trim(),
|
: messageController.text.trim(),
|
||||||
}),
|
}),
|
||||||
@@ -288,11 +277,10 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
|
|||||||
const Gap(8),
|
const Gap(8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FilledButton(
|
child: FilledButton(
|
||||||
onPressed:
|
onPressed: () =>
|
||||||
() => Navigator.of(context).pop(<String, dynamic>{
|
Navigator.of(context).pop(<String, dynamic>{
|
||||||
'recipient': selectedRecipient,
|
'recipient': selectedRecipient,
|
||||||
'message':
|
'message': messageController.text.trim().isEmpty
|
||||||
messageController.text.trim().isEmpty
|
|
||||||
? null
|
? null
|
||||||
: messageController.text.trim(),
|
: messageController.text.trim(),
|
||||||
}),
|
}),
|
||||||
@@ -336,8 +324,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
) {
|
) {
|
||||||
return stellarSubscriptionAsync.when(
|
return stellarSubscriptionAsync.when(
|
||||||
data: (membership) => _buildMembershipContent(context, ref, membership),
|
data: (membership) => _buildMembershipContent(context, ref, membership),
|
||||||
loading:
|
loading: () => Container(
|
||||||
() => Container(
|
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -353,8 +340,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
child: const Center(child: CircularProgressIndicator()),
|
child: const Center(child: CircularProgressIndicator()),
|
||||||
),
|
),
|
||||||
error:
|
error: (error, stack) => Container(
|
||||||
(error, stack) => Container(
|
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -393,7 +379,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
await client.post(
|
await client.post(
|
||||||
'/pass/subscriptions/${membership.identifier}/cancel',
|
'/wallet/subscriptions/${membership.identifier}/cancel',
|
||||||
);
|
);
|
||||||
ref.invalidate(accountStellarSubscriptionProvider);
|
ref.invalidate(accountStellarSubscriptionProvider);
|
||||||
ref.read(userInfoProvider.notifier).fetchUser();
|
ref.read(userInfoProvider.notifier).fetchUser();
|
||||||
@@ -544,8 +530,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children:
|
children: tiers.map((tier) {
|
||||||
tiers.map((tier) {
|
|
||||||
final isCurrentTier = currentMembership?.identifier == tier['id'];
|
final isCurrentTier = currentMembership?.identifier == tier['id'];
|
||||||
final tierColor = tier['color'] as Color;
|
final tierColor = tier['color'] as Color;
|
||||||
|
|
||||||
@@ -554,26 +539,20 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap:
|
onTap: isCurrentTier
|
||||||
isCurrentTier
|
|
||||||
? null
|
? null
|
||||||
: () => _purchaseMembership(
|
: () =>
|
||||||
context,
|
_purchaseMembership(context, ref, tier['id'] as String),
|
||||||
ref,
|
|
||||||
tier['id'] as String,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color: isCurrentTier
|
||||||
isCurrentTier
|
|
||||||
? tierColor.withOpacity(0.1)
|
? tierColor.withOpacity(0.1)
|
||||||
: Theme.of(context).colorScheme.surface,
|
: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color:
|
color: isCurrentTier
|
||||||
isCurrentTier
|
|
||||||
? tierColor
|
? tierColor
|
||||||
: Theme.of(
|
: Theme.of(
|
||||||
context,
|
context,
|
||||||
@@ -630,11 +609,9 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
tier['price'] as String,
|
tier['price'] as String,
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodyMedium
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodyMedium?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
|
||||||
Theme.of(
|
|
||||||
context,
|
context,
|
||||||
).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
@@ -646,8 +623,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
Icon(
|
Icon(
|
||||||
Icons.arrow_forward_ios,
|
Icons.arrow_forward_ios,
|
||||||
size: 16,
|
size: 16,
|
||||||
color:
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -704,7 +680,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final resp = await client.post(
|
final resp = await client.post(
|
||||||
'/pass/subscriptions',
|
'/wallet/subscriptions',
|
||||||
data: {
|
data: {
|
||||||
'identifier': tierId,
|
'identifier': tierId,
|
||||||
'payment_method': 'solian.wallet',
|
'payment_method': 'solian.wallet',
|
||||||
@@ -716,7 +692,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
final subscription = SnWalletSubscription.fromJson(resp.data);
|
final subscription = SnWalletSubscription.fromJson(resp.data);
|
||||||
if (subscription.status == 1) return;
|
if (subscription.status == 1) return;
|
||||||
final orderResp = await client.post(
|
final orderResp = await client.post(
|
||||||
'/pass/subscriptions/${subscription.identifier}/order',
|
'/wallet/subscriptions/${subscription.identifier}/order',
|
||||||
);
|
);
|
||||||
final order = SnWalletOrder.fromJson(orderResp.data);
|
final order = SnWalletOrder.fromJson(orderResp.data);
|
||||||
|
|
||||||
@@ -825,8 +801,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children:
|
children: tiers.map((tier) {
|
||||||
tiers.map((tier) {
|
|
||||||
final tierColor = tier['color'] as Color;
|
final tierColor = tier['color'] as Color;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
@@ -834,12 +809,8 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap:
|
onTap: () =>
|
||||||
() => _showPurchaseGiftDialog(
|
_showPurchaseGiftDialog(context, ref, tier['id'] as String),
|
||||||
context,
|
|
||||||
ref,
|
|
||||||
tier['id'] as String,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
@@ -877,11 +848,9 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
tier['price'] as String,
|
tier['price'] as String,
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodyMedium
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodyMedium?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
|
||||||
Theme.of(
|
|
||||||
context,
|
context,
|
||||||
).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
@@ -944,8 +913,8 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(Icons.redeem),
|
icon: Icon(Icons.redeem),
|
||||||
onPressed:
|
onPressed: () =>
|
||||||
() => _redeemGift(context, ref, codeController.text.trim()),
|
_redeemGift(context, ref, codeController.text.trim()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
@@ -966,16 +935,16 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
onPressed:
|
onPressed: () =>
|
||||||
() => _showGiftHistorySheet(context, ref, sentGifts, true),
|
_showGiftHistorySheet(context, ref, sentGifts, true),
|
||||||
child: Text('sentGifts'.tr()),
|
child: Text('sentGifts'.tr()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
onPressed:
|
onPressed: () =>
|
||||||
() => _showGiftHistorySheet(context, ref, receivedGifts, false),
|
_showGiftHistorySheet(context, ref, receivedGifts, false),
|
||||||
child: Text('receivedGifts'.tr()),
|
child: Text('receivedGifts'.tr()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -993,31 +962,21 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (context) => SheetScaffold(
|
||||||
(context) => SheetScaffold(
|
|
||||||
titleText: isSent ? 'sentGifts'.tr() : 'receivedGifts'.tr(),
|
titleText: isSent ? 'sentGifts'.tr() : 'receivedGifts'.tr(),
|
||||||
child: giftsAsync.when(
|
child: giftsAsync.when(
|
||||||
data:
|
data: (gifts) => gifts.isEmpty
|
||||||
(gifts) =>
|
|
||||||
gifts.isEmpty
|
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
isSent
|
isSent ? 'noSentGifts'.tr() : 'noReceivedGifts'.tr(),
|
||||||
? 'noSentGifts'.tr()
|
|
||||||
: 'noReceivedGifts'.tr(),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
padding: const EdgeInsets.only(top: 16),
|
padding: const EdgeInsets.only(top: 16),
|
||||||
itemCount: gifts.length,
|
itemCount: gifts.length,
|
||||||
itemBuilder:
|
itemBuilder: (context, index) =>
|
||||||
(context, index) => _buildGiftItem(
|
_buildGiftItem(context, ref, gifts[index], isSent),
|
||||||
context,
|
|
||||||
ref,
|
|
||||||
gifts[index],
|
|
||||||
isSent,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
error: (error, stack) => Center(child: Text('Error: $error')),
|
error: (error, stack) => Center(child: Text('Error: $error')),
|
||||||
@@ -1088,7 +1047,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (gift.status == 2 && gift.redeemer != null)
|
if (gift.status == 2 && gift.redeemer != null)
|
||||||
AccountPfcGestureDetector(
|
AccountPfcRegion(
|
||||||
uname: gift.redeemer!.name,
|
uname: gift.redeemer!.name,
|
||||||
child: ProfilePictureWidget(
|
child: ProfilePictureWidget(
|
||||||
file: gift.redeemer!.profile.picture,
|
file: gift.redeemer!.profile.picture,
|
||||||
@@ -1229,13 +1188,13 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final resp = await client.post(
|
final resp = await client.post(
|
||||||
'/pass/subscriptions/gifts/purchase',
|
'/wallet/subscriptions/gifts/purchase',
|
||||||
data: {
|
data: {
|
||||||
'subscription_identifier': subscriptionId,
|
'subscription_identifier': subscriptionId,
|
||||||
if (recipientId != null) 'recipient_id': recipientId,
|
'recipient_id': ?recipientId,
|
||||||
'payment_method': 'solian.wallet',
|
'payment_method': 'solian.wallet',
|
||||||
'payment_details': {'currency': 'golds'},
|
'payment_details': {'currency': 'golds'},
|
||||||
if (message != null) 'message': message,
|
'message': ?message,
|
||||||
'gift_duration_days': 30,
|
'gift_duration_days': 30,
|
||||||
'subscription_duration_days': 30,
|
'subscription_duration_days': 30,
|
||||||
},
|
},
|
||||||
@@ -1245,7 +1204,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
if (gift.status == 1) return; // Already paid
|
if (gift.status == 1) return; // Already paid
|
||||||
|
|
||||||
final orderResp = await client.post(
|
final orderResp = await client.post(
|
||||||
'/pass/subscriptions/gifts/${gift.id}/order',
|
'/wallet/subscriptions/gifts/${gift.id}/order',
|
||||||
);
|
);
|
||||||
final order = SnWalletOrder.fromJson(orderResp.data);
|
final order = SnWalletOrder.fromJson(orderResp.data);
|
||||||
|
|
||||||
@@ -1267,7 +1226,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Get the updated gift
|
// Get the updated gift
|
||||||
final giftResp = await client.get(
|
final giftResp = await client.get(
|
||||||
'/pass/subscriptions/gifts/${gift.id}',
|
'/wallet/subscriptions/gifts/${gift.id}',
|
||||||
);
|
);
|
||||||
final updatedGift = SnWalletGift.fromJson(giftResp.data);
|
final updatedGift = SnWalletGift.fromJson(giftResp.data);
|
||||||
|
|
||||||
@@ -1277,8 +1236,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await showModalBottomSheet(
|
await showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (context) => SheetScaffold(
|
||||||
(context) => SheetScaffold(
|
|
||||||
titleText: 'giftPurchased'.tr(),
|
titleText: 'giftPurchased'.tr(),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
@@ -1315,9 +1273,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
ClipboardData(text: updatedGift.giftCode),
|
ClipboardData(text: updatedGift.giftCode),
|
||||||
);
|
);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
showSnackBar(
|
showSnackBar('giftCodeCopiedToClipboard'.tr());
|
||||||
'giftCodeCopiedToClipboard'.tr(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.copy),
|
icon: const Icon(Icons.copy),
|
||||||
@@ -1335,13 +1291,8 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text(
|
Text(
|
||||||
'openGiftAnyoneCanRedeem'.tr(),
|
'openGiftAnyoneCanRedeem'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
context,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
).textTheme.bodySmall?.copyWith(
|
|
||||||
color:
|
|
||||||
Theme.of(
|
|
||||||
context,
|
|
||||||
).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -1377,7 +1328,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
|
|
||||||
// First check if gift can be redeemed
|
// First check if gift can be redeemed
|
||||||
final checkResp = await client.get(
|
final checkResp = await client.get(
|
||||||
'/pass/subscriptions/gifts/check/$giftCode',
|
'/wallet/subscriptions/gifts/check/$giftCode',
|
||||||
);
|
);
|
||||||
final checkData = checkResp.data as Map<String, dynamic>;
|
final checkData = checkResp.data as Map<String, dynamic>;
|
||||||
|
|
||||||
@@ -1389,7 +1340,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Redeem the gift
|
// Redeem the gift
|
||||||
await client.post(
|
await client.post(
|
||||||
'/pass/subscriptions/gifts/redeem',
|
'/wallet/subscriptions/gifts/redeem',
|
||||||
data: {'gift_code': giftCode},
|
data: {'gift_code': giftCode},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1397,8 +1348,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
hideLoadingModal(context);
|
hideLoadingModal(context);
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (context) => AlertDialog(
|
||||||
(context) => AlertDialog(
|
|
||||||
title: Text('giftRedeemed'.tr()),
|
title: Text('giftRedeemed'.tr()),
|
||||||
content: Text('giftRedeemedSuccessfully'.tr()),
|
content: Text('giftRedeemedSuccessfully'.tr()),
|
||||||
actions: [
|
actions: [
|
||||||
@@ -1434,7 +1384,7 @@ class StellarProgramTab extends HookConsumerWidget {
|
|||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
try {
|
try {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
await client.post('/pass/subscriptions/gifts/${gift.id}/cancel');
|
await client.post('/wallet/subscriptions/gifts/${gift.id}/cancel');
|
||||||
ref.invalidate(accountSentGiftsProvider);
|
ref.invalidate(accountSentGiftsProvider);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
hideLoadingModal(context);
|
hideLoadingModal(context);
|
||||||
@@ -50,7 +50,7 @@ final class AccountStellarSubscriptionProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$accountStellarSubscriptionHash() =>
|
String _$accountStellarSubscriptionHash() =>
|
||||||
r'7cdfc7ca29aac240fc8704f4493498d87f307400';
|
r'fd0aa9b7110e5d0ba68d8a57bd0e4dc191586e3b';
|
||||||
|
|
||||||
@ProviderFor(accountSentGifts)
|
@ProviderFor(accountSentGifts)
|
||||||
final accountSentGiftsProvider = AccountSentGiftsFamily._();
|
final accountSentGiftsProvider = AccountSentGiftsFamily._();
|
||||||
@@ -109,7 +109,7 @@ final class AccountSentGiftsProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$accountSentGiftsHash() => r'460af8d22e16dc402848cb94e9b8a8a26d023c41';
|
String _$accountSentGiftsHash() => r'9fa99729b9efa1a74695645ee1418677b5e63027';
|
||||||
|
|
||||||
final class AccountSentGiftsFamily extends $Family
|
final class AccountSentGiftsFamily extends $Family
|
||||||
with
|
with
|
||||||
@@ -198,7 +198,7 @@ final class AccountReceivedGiftsProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$accountReceivedGiftsHash() =>
|
String _$accountReceivedGiftsHash() =>
|
||||||
r'1208c27cca49e154af073071a197b37a2703f56d';
|
r'b9e9ad5e8de8916f881ceeca7f2032f344c5c58b';
|
||||||
|
|
||||||
final class AccountReceivedGiftsFamily extends $Family
|
final class AccountReceivedGiftsFamily extends $Family
|
||||||
with
|
with
|
||||||
@@ -280,7 +280,7 @@ final class AccountGiftProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$accountGiftHash() => r'70ca553e0b84cba9dfbee428f9bf44207138713a';
|
String _$accountGiftHash() => r'78890be44865accadeabdc26a96447bb3e841a5d';
|
||||||
|
|
||||||
final class AccountGiftFamily extends $Family
|
final class AccountGiftFamily extends $Family
|
||||||
with $FunctionalFamilyOverride<FutureOr<SnWalletGift>, String> {
|
with $FunctionalFamilyOverride<FutureOr<SnWalletGift>, String> {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:island/models/activitypub.dart';
|
import 'package:island/core/models/activitypub.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
|
||||||
class ApActorListItem extends StatelessWidget {
|
class ApActorListItem extends StatelessWidget {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:island/models/activitypub.dart';
|
import 'package:island/core/models/activitypub.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
|
||||||
class ActorPictureWidget extends StatelessWidget {
|
class ActorPictureWidget extends StatelessWidget {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:island/models/activitypub.dart';
|
import 'package:island/core/models/activitypub.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:relative_time/relative_time.dart';
|
import 'package:relative_time/relative_time.dart';
|
||||||
|
|
||||||
@@ -7,15 +7,15 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/accounts/accounts_widgets/account/event_calendar_content.dart';
|
||||||
import 'package:island/models/fortune.dart';
|
import 'package:island/core/models/activity.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/accounts/accounts_models/fortune.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/screens/auth/captcha.dart';
|
import 'package:island/accounts/accounts_pod.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/auth/captcha.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/shared/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/drive/drive_widgets/cloud_files.dart';
|
||||||
import 'package:island/widgets/account/event_calendar_content.dart';
|
import 'package:island/drive/content/sheet_scaffold.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:island/models/activity.dart';
|
import 'package:island/core/models/activity.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'event_calendar.g.dart';
|
part 'event_calendar.g.dart';
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:island/utils/format.dart';
|
import 'package:island/core/format.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
class UsageOverviewWidget extends StatelessWidget {
|
class UsageOverviewWidget extends StatelessWidget {
|
||||||
@@ -112,12 +112,12 @@ class UsageOverviewWidget extends StatelessWidget {
|
|||||||
Colors.purple,
|
Colors.purple,
|
||||||
];
|
];
|
||||||
return PieChartData(
|
return PieChartData(
|
||||||
sections:
|
sections: pools.asMap().entries.map((entry) {
|
||||||
pools.asMap().entries.map((entry) {
|
|
||||||
final pool = entry.value as Map<String, dynamic>;
|
final pool = entry.value as Map<String, dynamic>;
|
||||||
final title = pool['pool_name'] as String;
|
final title = pool['pool_name'] as String;
|
||||||
final truncatedTitle =
|
final truncatedTitle = title.length > 8
|
||||||
title.length > 8 ? '${title.substring(0, 8)}...' : title;
|
? '${title.substring(0, 8)}...'
|
||||||
|
: title;
|
||||||
return PieChartSectionData(
|
return PieChartSectionData(
|
||||||
value: (pool['usage_bytes'] as num).toDouble(),
|
value: (pool['usage_bytes'] as num).toDouble(),
|
||||||
title: truncatedTitle,
|
title: truncatedTitle,
|
||||||
@@ -4,8 +4,8 @@ import 'dart:io';
|
|||||||
import 'package:dio/dio.dart' hide Response;
|
import 'package:dio/dio.dart' hide Response;
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/core/models/activity.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:island/talker.dart';
|
import 'package:island/talker.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:shelf/shelf.dart';
|
import 'package:shelf/shelf.dart';
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/accounts/accounts_models/account.dart';
|
||||||
|
|
||||||
String? getActivityTitle(String? label, Map<String, dynamic>? meta) {
|
String? getActivityTitle(String? label, Map<String, dynamic>? meta) {
|
||||||
if (meta == null) return label;
|
if (meta == null) return label;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:island/pods/network.dart';
|
import 'package:island/core/network.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'captcha.config.g.dart';
|
part 'captcha.config.g.dart';
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user