Compare commits
20 Commits
3.2.0+129
...
ecc100ac45
Author | SHA1 | Date | |
---|---|---|---|
ecc100ac45 | |||
573b76d3ff | |||
f7dad5e419 | |||
9f2f1c0848 | |||
580d9fd979 | |||
3b375abc09 | |||
c527b5e67c | |||
e9f09bbe54 | |||
3aece9316c | |||
a61c889c6c | |||
0dd3221a56 | |||
66918521f8 | |||
bb1846e462 | |||
a976a6eaf4 | |||
4252f66fd3 | |||
f2d780b48f | |||
300541f9bb | |||
43787bb813 | |||
3417c51a3b | |||
f98e603e82 |
@@ -62,4 +62,3 @@ If you want to build the release version, use the flutter build command. Learn m
|
||||
```bash
|
||||
flutter build <platform>
|
||||
```
|
||||
|
||||
|
@@ -338,6 +338,7 @@
|
||||
"notifications": "Notifications",
|
||||
"posts": "Posts",
|
||||
"settingsBackgroundImage": "Background Image",
|
||||
"settingsBackgroundImageEnable": "Show Background Image",
|
||||
"settingsBackgroundImageClear": "Clear Background Image",
|
||||
"settingsBackgroundGenerateColor": "Generate color scheme from Bacground Image",
|
||||
"messageNone": "No content to display",
|
||||
@@ -634,8 +635,9 @@
|
||||
"chatJoin": "Join the Chat",
|
||||
"realmJoin": "Join the Realm",
|
||||
"realmJoinSuccess": "Successfully joined the realm.",
|
||||
"discoverRealms": "Discover realms",
|
||||
"discoverPublishers": "Discover publishers",
|
||||
"discoverRealms": "Realms",
|
||||
"discoverPublishers": "Publishers",
|
||||
"discoverShuffledPost": "Random Posts",
|
||||
"search": "Search",
|
||||
"publisherMembers": "Collaborators",
|
||||
"developerHub": "Developer Hub",
|
||||
@@ -693,7 +695,7 @@
|
||||
"publisherFeatureDevelopDescription": "Unlock development abilities for your publisher, including custom apps, API keys, and more.",
|
||||
"publisherFeatureDevelopHint": "Currently, this feature is under active development, you need send a request to unlock this feature.",
|
||||
"learnMore": "Learn More",
|
||||
"discoverWebArticles": "Articles from external sites",
|
||||
"discoverWebArticles": "Web Feed Articles",
|
||||
"webArticlesStand": "Article Stand",
|
||||
"about": "About",
|
||||
"membershipCancel": "Cancel Membership",
|
||||
@@ -951,7 +953,6 @@
|
||||
"chatBreak15m": "15m",
|
||||
"chatBreak30m": "30m",
|
||||
"chatBreakCustomMinutes": "Custom (minutes)",
|
||||
"chatBreakEnterMinutes": "Enter minutes",
|
||||
"errorGeneric": "Error: {}",
|
||||
"searchMessages": "Search Messages",
|
||||
"messagesCount": "{} messages",
|
||||
@@ -960,5 +961,15 @@
|
||||
"searchMessagesHint": "Search messages...",
|
||||
"searchLinks": "Links",
|
||||
"searchAttachments": "Attachments",
|
||||
"noMessagesFound": "No messages found"
|
||||
}
|
||||
"noMessagesFound": "No messages found",
|
||||
"openInBrowser": "Open in Browser",
|
||||
"highlightPost": "Highlight Post",
|
||||
"filters": "Filters",
|
||||
"apply": "Apply",
|
||||
"pubName": "Pub Name",
|
||||
"realm": "Realm",
|
||||
"shuffle": "Shuffle",
|
||||
"pinned": "Pinned",
|
||||
"noResultsFound": "No results found",
|
||||
"toggleFilters": "Toggle filters"
|
||||
}
|
||||
|
@@ -304,6 +304,7 @@
|
||||
"notifications": "通知",
|
||||
"posts": "帖子",
|
||||
"settingsBackgroundImage": "背景图片",
|
||||
"settingsBackgroundImageEnable": "显示背景图片",
|
||||
"settingsBackgroundImageClear": "清除背景图片",
|
||||
"settingsBackgroundGenerateColor": "从背景图像生成主题色",
|
||||
"messageNone": "没有内容可显示",
|
||||
@@ -857,5 +858,7 @@
|
||||
"expiresIn": "过期时间(秒)",
|
||||
"isOidc": "OIDC 兼容",
|
||||
"statusPresent": "至今",
|
||||
"accountAutomated": "机器人"
|
||||
"accountAutomated": "机器人",
|
||||
"openInBrowser": "在浏览器中打开",
|
||||
"highlightPost": "精选帖子"
|
||||
}
|
||||
|
@@ -303,7 +303,8 @@
|
||||
"notifications": "通知",
|
||||
"posts": "帖子",
|
||||
"settingsBackgroundImage": "背景圖片",
|
||||
"settingsBackgroundImageClear": "清除背景圖片",
|
||||
"settingsBackgroundImageEnable": "顯示背景圖片",
|
||||
"settingsBackgroundImageClear": "清除背景圖片",
|
||||
"settingsBackgroundGenerateColor": "從背景圖像生成主題色",
|
||||
"messageNone": "沒有內容可顯示",
|
||||
"unreadMessages": {
|
||||
|
12
assets/icons/icon-outline.svg
Normal file
12
assets/icons/icon-outline.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" fill="none">
|
||||
<path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="12"
|
||||
d="M54 147h86" />
|
||||
<path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="10"
|
||||
d="M57 111s-2-4.5-2-10m22 22s-4 7-11 4m9-22s-2-4.5-2-10" />
|
||||
<path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="12"
|
||||
d="M54 147a32 32 0 0 1-11.999-61.665A39 39 0 0 1 81 46m59 101a30 30 0 0 0 29.933-28" />
|
||||
<circle cx="132" cy="75" r="4" stroke="#fff" stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="8" />
|
||||
<path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="10"
|
||||
d="M112.5 41.217C100.843 47.961 93 60.564 93 75c0 6.375 1.53 12.393 4.242 17.707m69.513-35.419A38.84 38.84 0 0 1 171 75c0 14.433-7.84 27.034-19.493 33.779m-.793-43.317A20.9 20.9 0 0 1 153 75c0 7.77-4.221 14.556-10.495 18.188m-21.003-36.38C115.224 60.44 111 67.226 111 75a20.9 20.9 0 0 0 2.284 9.533" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/images/media-offline.jpg
Normal file
BIN
assets/images/media-offline.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 461 KiB |
Binary file not shown.
Before Width: | Height: | Size: 307 KiB |
@@ -21,6 +21,6 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>12.0</string>
|
||||
<string>13.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
156
ios/Podfile.lock
156
ios/Podfile.lock
@@ -42,83 +42,83 @@ PODS:
|
||||
- Flutter
|
||||
- file_saver (0.0.1):
|
||||
- Flutter
|
||||
- Firebase/CoreOnly (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- Firebase/Crashlytics (12.0.0):
|
||||
- Firebase/CoreOnly (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- Firebase/Crashlytics (12.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseCrashlytics (~> 12.0.0)
|
||||
- Firebase/Messaging (12.0.0):
|
||||
- FirebaseCrashlytics (~> 12.2.0)
|
||||
- Firebase/Messaging (12.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 12.0.0)
|
||||
- firebase_analytics (12.0.0):
|
||||
- FirebaseMessaging (~> 12.2.0)
|
||||
- firebase_analytics (12.0.1):
|
||||
- firebase_core
|
||||
- FirebaseAnalytics (= 12.0.0)
|
||||
- FirebaseAnalytics (= 12.2.0)
|
||||
- Flutter
|
||||
- firebase_core (4.0.0):
|
||||
- Firebase/CoreOnly (= 12.0.0)
|
||||
- firebase_core (4.1.0):
|
||||
- Firebase/CoreOnly (= 12.2.0)
|
||||
- Flutter
|
||||
- firebase_crashlytics (5.0.0):
|
||||
- Firebase/Crashlytics (= 12.0.0)
|
||||
- firebase_crashlytics (5.0.1):
|
||||
- Firebase/Crashlytics (= 12.2.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_messaging (16.0.0):
|
||||
- Firebase/Messaging (= 12.0.0)
|
||||
- firebase_messaging (16.0.1):
|
||||
- Firebase/Messaging (= 12.2.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseAnalytics (12.0.0):
|
||||
- FirebaseAnalytics/Default (= 12.0.0)
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseAnalytics (12.2.0):
|
||||
- FirebaseAnalytics/Default (= 12.2.0)
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseAnalytics/Default (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- GoogleAppMeasurement/Default (= 12.0.0)
|
||||
- FirebaseAnalytics/Default (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleAppMeasurement/Default (= 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseCore (12.0.0):
|
||||
- FirebaseCoreInternal (~> 12.0.0)
|
||||
- FirebaseCore (12.2.0):
|
||||
- FirebaseCoreInternal (~> 12.2.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Logger (~> 8.1)
|
||||
- FirebaseCoreExtension (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseCoreInternal (12.0.0):
|
||||
- FirebaseCoreExtension (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseCoreInternal (12.2.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- FirebaseCrashlytics (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseRemoteConfigInterop (~> 12.0.0)
|
||||
- FirebaseSessions (~> 12.0.0)
|
||||
- FirebaseCrashlytics (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- FirebaseRemoteConfigInterop (~> 12.2.0)
|
||||
- FirebaseSessions (~> 12.2.0)
|
||||
- GoogleDataTransport (~> 10.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseInstallations (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseMessaging (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseMessaging (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleDataTransport (~> 10.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Reachability (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseRemoteConfigInterop (12.0.0)
|
||||
- FirebaseSessions (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseCoreExtension (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseRemoteConfigInterop (12.2.0)
|
||||
- FirebaseSessions (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseCoreExtension (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleDataTransport (~> 10.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
@@ -147,33 +147,33 @@ PODS:
|
||||
- flutter_udid (0.0.1):
|
||||
- Flutter
|
||||
- SAMKeychain
|
||||
- flutter_webrtc (1.0.0):
|
||||
- flutter_webrtc (1.1.0):
|
||||
- Flutter
|
||||
- WebRTC-SDK (= 137.7151.02)
|
||||
- WebRTC-SDK (= 137.7151.03)
|
||||
- gal (1.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- GoogleAdsOnDeviceConversion (2.1.0):
|
||||
- GoogleAdsOnDeviceConversion (2.3.0):
|
||||
- GoogleUtilities/Logger (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/Core (12.0.0):
|
||||
- GoogleAppMeasurement/Core (12.2.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/Default (12.0.0):
|
||||
- GoogleAdsOnDeviceConversion (= 2.1.0)
|
||||
- GoogleAppMeasurement/Core (= 12.0.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (= 12.0.0)
|
||||
- GoogleAppMeasurement/Default (12.2.0):
|
||||
- GoogleAdsOnDeviceConversion (= 2.3.0)
|
||||
- GoogleAppMeasurement/Core (= 12.2.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (= 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (12.0.0):
|
||||
- GoogleAppMeasurement/Core (= 12.0.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (12.2.0):
|
||||
- GoogleAppMeasurement/Core (= 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
@@ -217,7 +217,7 @@ PODS:
|
||||
- livekit_client (2.5.0):
|
||||
- Flutter
|
||||
- flutter_webrtc
|
||||
- WebRTC-SDK (= 137.7151.02)
|
||||
- WebRTC-SDK (= 137.7151.03)
|
||||
- local_auth_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
@@ -250,9 +250,9 @@ PODS:
|
||||
- record_ios (1.1.0):
|
||||
- Flutter
|
||||
- SAMKeychain (1.5.3)
|
||||
- SDWebImage (5.21.1):
|
||||
- SDWebImage/Core (= 5.21.1)
|
||||
- SDWebImage/Core (5.21.1)
|
||||
- SDWebImage (5.21.2):
|
||||
- SDWebImage/Core (= 5.21.2)
|
||||
- SDWebImage/Core (5.21.2)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
@@ -297,7 +297,7 @@ PODS:
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
- WebRTC-SDK (137.7151.02)
|
||||
- WebRTC-SDK (137.7151.03)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Alamofire
|
||||
@@ -470,21 +470,21 @@ SPEC CHECKSUMS:
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||
Firebase: 800d487043c0557d9faed71477a38d9aafb08a41
|
||||
firebase_analytics: cd56fc56f75c1df30a6ff5290cd56e230996a76d
|
||||
firebase_core: 633e1851ffe1b9ab875f6467a4f574c79cef02e4
|
||||
firebase_crashlytics: 2c6c1a17900a38081d938330e9f48e60ec5b255d
|
||||
firebase_messaging: d17feef781edc84ebefe62624fb384358ad96361
|
||||
FirebaseAnalytics: 6d790cd1b159b4eb61a99948df0934ce505a34f7
|
||||
FirebaseCore: 055f4ab117d5964158c833f3d5e7ec6d91648d4a
|
||||
FirebaseCoreExtension: 639afb3de6abd611952be78a794c54a47fa0f361
|
||||
FirebaseCoreInternal: dedc28e569a4be85f38f3d6af1070a2e12018d55
|
||||
FirebaseCrashlytics: db75aa0cab8d00f68406fa247c32fe17ade884d7
|
||||
FirebaseInstallations: d4c7c958f99c8860d7fcece786314ae790e2f988
|
||||
FirebaseMessaging: af49f8d7c0a3d2a017d9302c80946f45a7777dde
|
||||
FirebaseRemoteConfigInterop: bfa0ea72ba3dc5af739777296424e46bd6f42613
|
||||
FirebaseSessions: 4e784acda213108aafef536535cdfc03504acc42
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
Firebase: 26f6f8d460603af3df970ad505b16b15f5e2e9a1
|
||||
firebase_analytics: 111ff65791a430356bd6c7e4d7339537fc6a15ae
|
||||
firebase_core: 3ff52146406557dddd01d570e807e203ec7e1302
|
||||
firebase_crashlytics: 3637078b718a52dc9fb4d64e37c969e86b87ff6f
|
||||
firebase_messaging: 3dcc998dd98e1e54af75d0cccae8606eba43553c
|
||||
FirebaseAnalytics: e04e23bc070e3014aa5cf4980f9df7ce5cd79ec8
|
||||
FirebaseCore: 311c48a147ad4a0ab7febbaed89e8025c67510cd
|
||||
FirebaseCoreExtension: 73af080c22a2f7b44cefa391dc08f7e4ee162cb5
|
||||
FirebaseCoreInternal: 56ea29f3dad2894f81b060f706f9d53509b6ed3b
|
||||
FirebaseCrashlytics: f83cbf176d5c637ade108c0aacf1ccbd5ec499bf
|
||||
FirebaseInstallations: 3e884b01feabdf67582a80f3250425a00979b4ed
|
||||
FirebaseMessaging: 43ec73bbfedd0c385a849bb91593ab4ad4b9e48e
|
||||
FirebaseRemoteConfigInterop: 0896fd52ab72586a355c8f389ff85aaa9e5375e1
|
||||
FirebaseSessions: f4692789e770bec66ce17d772c0e9561c4f11737
|
||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||
flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9
|
||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
||||
@@ -493,16 +493,16 @@ SPEC CHECKSUMS:
|
||||
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
|
||||
flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544
|
||||
flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9
|
||||
flutter_webrtc: 6f7da106613d52ade777d5b4875a43f48c28b457
|
||||
flutter_webrtc: b0b2e04411747142962164a1cfa43a1af9a0afac
|
||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||
GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64
|
||||
GoogleAppMeasurement: 8f6ab04ad6ae493b53fcf56bd26323fb2f1384f3
|
||||
GoogleAdsOnDeviceConversion: 9090c435cde08903e8dd1ba2c77fbec9e46d9afe
|
||||
GoogleAppMeasurement: 09f341dfa8527d1612a09cbfe809a242c0b737af
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
||||
Kingfisher: ff0d31a1f07bdff6a1ebb3ba08b8e6e567b6500c
|
||||
livekit_client: e3b79b99405428aac439b6b76a254cd9a11dbbfb
|
||||
livekit_client: f810c81bbbc229a84f60b09e66603ac4e93f7599
|
||||
local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19
|
||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||
@@ -518,7 +518,7 @@ SPEC CHECKSUMS:
|
||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
SDWebImage: f29024626962457f3470184232766516dee8dfea
|
||||
SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||
sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418
|
||||
@@ -530,7 +530,7 @@ SPEC CHECKSUMS:
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
WebRTC-SDK: d20de357dcbf7c9696b124b39f3ff62125107e4b
|
||||
WebRTC-SDK: 69d4e56b0b4b27d788e87bab9b9a1326ed05b1e3
|
||||
|
||||
PODFILE CHECKSUM: c818292390b02fa379036ea099713a332bd7193f
|
||||
|
||||
|
@@ -853,7 +853,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -897,6 +897,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -915,6 +916,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -931,6 +933,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1078,7 +1081,7 @@
|
||||
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -1121,7 +1124,7 @@
|
||||
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -1161,7 +1164,7 @@
|
||||
INFOPLIST_FILE = SolianShareExtension/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SolianShareExtension;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -1348,7 +1351,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -1399,7 +1402,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
@@ -30,7 +30,6 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
|
||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:flutter_langdetect/flutter_langdetect.dart' as langdetect;
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
@@ -52,7 +51,6 @@ void main() async {
|
||||
}
|
||||
|
||||
try {
|
||||
await langdetect.initLangDetect();
|
||||
await EasyLocalization.ensureInitialized();
|
||||
|
||||
if (kIsWeb || !Platform.isLinux) {
|
||||
@@ -225,6 +223,7 @@ class IslandApp extends HookConsumerWidget {
|
||||
if (user.value != null) {
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
subscribePushNotification(apiClient);
|
||||
initializeLocalNotifications();
|
||||
final wsNotifier = ref.read(websocketStateProvider.notifier);
|
||||
wsNotifier.connect();
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/services/text.dart';
|
||||
import 'package:island/utils/text.dart';
|
||||
|
||||
part 'post_category.freezed.dart';
|
||||
part 'post_category.g.dart';
|
||||
|
@@ -15,6 +15,7 @@ const kNetworkServerStoreKey = 'app_server_url';
|
||||
|
||||
const kAppbarTransparentStoreKey = 'app_bar_transparent';
|
||||
const kAppBackgroundStoreKey = 'app_has_background';
|
||||
const kAppShowBackgroundImage = 'app_show_background_image';
|
||||
const kAppColorSchemeStoreKey = 'app_color_scheme';
|
||||
const kAppNotifyWithHaptic = 'app_notify_with_haptic';
|
||||
const kAppCustomFonts = 'app_custom_fonts';
|
||||
@@ -58,6 +59,7 @@ sealed class AppSettings with _$AppSettings {
|
||||
required bool aprilFoolFeatures,
|
||||
required bool enterToSend,
|
||||
required bool appBarTransparent,
|
||||
required bool showBackgroundImage,
|
||||
required String? customFonts,
|
||||
required int? appColorScheme, // The color stored via the int type
|
||||
required Size? windowSize, // The window size for desktop platforms
|
||||
@@ -75,6 +77,7 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
||||
aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true,
|
||||
enterToSend: prefs.getBool(kAppEnterToSend) ?? true,
|
||||
appBarTransparent: prefs.getBool(kAppbarTransparentStoreKey) ?? false,
|
||||
showBackgroundImage: prefs.getBool(kAppShowBackgroundImage) ?? true,
|
||||
customFonts: prefs.getString(kAppCustomFonts),
|
||||
appColorScheme: prefs.getInt(kAppColorSchemeStoreKey),
|
||||
windowSize: _getWindowSizeFromPrefs(prefs),
|
||||
@@ -129,6 +132,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
||||
ref.read(themeProvider.notifier).reloadTheme();
|
||||
}
|
||||
|
||||
void setShowBackgroundImage(bool value) {
|
||||
final prefs = ref.read(sharedPreferencesProvider);
|
||||
prefs.setBool(kAppShowBackgroundImage, value);
|
||||
state = state.copyWith(showBackgroundImage: value);
|
||||
}
|
||||
|
||||
void setCustomFonts(String? value) {
|
||||
final prefs = ref.read(sharedPreferencesProvider);
|
||||
prefs.setString(kAppCustomFonts, value ?? '');
|
||||
|
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$AppSettings {
|
||||
|
||||
bool get autoTranslate; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get appBarTransparent; String? get customFonts; int? get appColorScheme;// The color stored via the int type
|
||||
bool get autoTranslate; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get appBarTransparent; bool get showBackgroundImage; String? get customFonts; int? get appColorScheme;// The color stored via the int type
|
||||
Size? get windowSize;
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -26,16 +26,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme,windowSize);
|
||||
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)';
|
||||
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)';
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
|
||||
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme, Size? windowSize
|
||||
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize
|
||||
});
|
||||
|
||||
|
||||
@@ -63,13 +63,14 @@ class _$AppSettingsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||
as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable
|
||||
as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable
|
||||
as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable
|
||||
as bool,showBackgroundImage: null == showBackgroundImage ? _self.showBackgroundImage : showBackgroundImage // ignore: cast_nullable_to_non_nullable
|
||||
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
|
||||
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
|
||||
as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable
|
||||
@@ -155,10 +156,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme, Size? windowSize)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettings() when $default != null:
|
||||
return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.customFonts,_that.appColorScheme,_that.windowSize);case _:
|
||||
return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -176,10 +177,10 @@ return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme, Size? windowSize) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettings():
|
||||
return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.customFonts,_that.appColorScheme,_that.windowSize);}
|
||||
return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -193,10 +194,10 @@ return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme, Size? windowSize)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppSettings() when $default != null:
|
||||
return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.customFonts,_that.appColorScheme,_that.windowSize);case _:
|
||||
return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.windowSize);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -208,7 +209,7 @@ return $default(_that.autoTranslate,_that.soundEffects,_that.aprilFoolFeatures,_
|
||||
|
||||
|
||||
class _AppSettings implements AppSettings {
|
||||
const _AppSettings({required this.autoTranslate, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.customFonts, required this.appColorScheme, required this.windowSize});
|
||||
const _AppSettings({required this.autoTranslate, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.windowSize});
|
||||
|
||||
|
||||
@override final bool autoTranslate;
|
||||
@@ -216,6 +217,7 @@ class _AppSettings implements AppSettings {
|
||||
@override final bool aprilFoolFeatures;
|
||||
@override final bool enterToSend;
|
||||
@override final bool appBarTransparent;
|
||||
@override final bool showBackgroundImage;
|
||||
@override final String? customFonts;
|
||||
@override final int? appColorScheme;
|
||||
// The color stored via the int type
|
||||
@@ -231,16 +233,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme,windowSize);
|
||||
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,windowSize);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)';
|
||||
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, windowSize: $windowSize)';
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +253,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
|
||||
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme, Size? windowSize
|
||||
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, Size? windowSize
|
||||
});
|
||||
|
||||
|
||||
@@ -268,13 +270,14 @@ class __$AppSettingsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? windowSize = freezed,}) {
|
||||
return _then(_AppSettings(
|
||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||
as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable
|
||||
as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable
|
||||
as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable
|
||||
as bool,showBackgroundImage: null == showBackgroundImage ? _self.showBackgroundImage : showBackgroundImage // ignore: cast_nullable_to_non_nullable
|
||||
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
|
||||
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
|
||||
as int?,windowSize: freezed == windowSize ? _self.windowSize : windowSize // ignore: cast_nullable_to_non_nullable
|
||||
|
@@ -7,7 +7,7 @@ part of 'config.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$appSettingsNotifierHash() =>
|
||||
r'c4f40a3bc4311c6360c2b5e44f8df5e5d7c1bd75';
|
||||
r'e3c13307eabb0201487b85ab67b1ab493e588e71';
|
||||
|
||||
/// See also [AppSettingsNotifier].
|
||||
@ProviderFor(AppSettingsNotifier)
|
||||
|
@@ -1,11 +1,9 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_langdetect/flutter_langdetect.dart' as langdetect;
|
||||
|
||||
part 'translate.freezed.dart';
|
||||
part 'translate.g.dart';
|
||||
@@ -29,10 +27,17 @@ Future<String> translateString(Ref ref, TranslateQuery query) async {
|
||||
|
||||
@riverpod
|
||||
String? detectStringLanguage(Ref ref, String text) {
|
||||
try {
|
||||
return langdetect.detectLangs(text).firstOrNull?.lang;
|
||||
} catch (err) {
|
||||
log('[Language] Unable to detect text\'s language: $text');
|
||||
return null;
|
||||
bool isChinese(String text) {
|
||||
final chineseRegex = RegExp(r'[\u4e00-\u9fff]');
|
||||
return chineseRegex.hasMatch(text);
|
||||
}
|
||||
|
||||
bool isEnglish(String text) {
|
||||
final englishRegex = RegExp(r'[a-zA-Z]');
|
||||
return englishRegex.hasMatch(text) && !isChinese(text);
|
||||
}
|
||||
|
||||
if (isChinese(text)) return "zh";
|
||||
if (isEnglish(text)) return "en";
|
||||
return null;
|
||||
}
|
||||
|
@@ -149,7 +149,7 @@ class _TranslateStringProviderElement
|
||||
}
|
||||
|
||||
String _$detectStringLanguageHash() =>
|
||||
r'697b68464b3d00927cc43ccc1ba8ba93f2a470ed';
|
||||
r'24fbf52edbbffcc8dc4f09f7206f82d69728e703';
|
||||
|
||||
/// See also [detectStringLanguage].
|
||||
@ProviderFor(detectStringLanguage)
|
||||
|
@@ -68,6 +68,7 @@ class AccountScreen extends HookConsumerWidget {
|
||||
body: SingleChildScrollView(
|
||||
padding: getTabbedPadding(context),
|
||||
child: Column(
|
||||
spacing: 4,
|
||||
children: <Widget>[
|
||||
Card(
|
||||
child: Column(
|
||||
@@ -112,20 +113,22 @@ class AccountScreen extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
AccountName(
|
||||
account: user.value!,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
Flexible(
|
||||
child: AccountName(
|
||||
account: user.value!,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text('@${user.value!.name}'),
|
||||
Flexible(child: Text('@${user.value!.name}')),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
(user.value!.profile.bio.isNotEmpty)
|
||||
? user.value!.profile.bio
|
||||
: 'No description yet.',
|
||||
: 'descriptionNone'.tr(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -158,8 +161,16 @@ class AccountScreen extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Symbols.draw, size: 28).padding(bottom: 8),
|
||||
Text('creatorHub').tr().fontSize(16).bold(),
|
||||
Text('creatorHubDescription').tr(),
|
||||
Text(
|
||||
'creatorHub',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).tr().fontSize(16).bold(),
|
||||
Text(
|
||||
'creatorHubDescription',
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).tr(),
|
||||
],
|
||||
).padding(horizontal: 16, vertical: 12),
|
||||
onTap: () {
|
||||
@@ -176,8 +187,16 @@ class AccountScreen extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Symbols.code, size: 28).padding(bottom: 8),
|
||||
Text('developerPortal').tr().fontSize(16).bold(),
|
||||
Text('developerPortalDescription').tr(),
|
||||
Text(
|
||||
'developerPortal',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).tr().fontSize(16).bold(),
|
||||
Text(
|
||||
'developerPortalDescription',
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).tr(),
|
||||
],
|
||||
).padding(horizontal: 16, vertical: 12),
|
||||
onTap: () {
|
||||
|
@@ -14,7 +14,6 @@ import 'package:island/screens/account/me/settings_connections.dart';
|
||||
import 'package:island/screens/account/me/settings_contacts.dart';
|
||||
import 'package:island/screens/auth/captcha.dart';
|
||||
import 'package:island/screens/auth/login.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/account/account_devices.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
@@ -57,7 +56,6 @@ class AccountSettingsScreen extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isDesktop =
|
||||
!kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux);
|
||||
final isWide = isWideScreen(context);
|
||||
|
||||
Future<void> requestAccountDeletion() async {
|
||||
final confirm = await showConfirmAlert(
|
||||
@@ -440,51 +438,19 @@ class AccountSettingsScreen extends HookConsumerWidget {
|
||||
|
||||
// Create a responsive layout based on screen width
|
||||
Widget buildSettingsList() {
|
||||
if (isWide) {
|
||||
// Two-column layout for wide screens
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_SettingsSection(
|
||||
title: 'accountSecurityTitle',
|
||||
children: securitySettings,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_SettingsSection(
|
||||
title: 'accountDangerZoneTitle',
|
||||
children: dangerZoneSettings,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
// Single column layout for narrow screens
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_SettingsSection(
|
||||
title: 'accountSecurityTitle',
|
||||
children: securitySettings,
|
||||
),
|
||||
_SettingsSection(
|
||||
title: 'accountDangerZoneTitle',
|
||||
children: dangerZoneSettings,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_SettingsSection(
|
||||
title: 'accountSecurityTitle',
|
||||
children: securitySettings,
|
||||
),
|
||||
_SettingsSection(
|
||||
title: 'accountDangerZoneTitle',
|
||||
children: dangerZoneSettings,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return AppScaffold(
|
||||
|
@@ -1,14 +1,16 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/auth.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/account/me/account_settings.dart';
|
||||
import 'package:island/screens/auth/oidc.native.dart';
|
||||
import 'package:island/services/text.dart';
|
||||
import 'package:island/utils/text.dart';
|
||||
import 'package:island/services/time.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
@@ -16,6 +18,7 @@ import 'package:island/widgets/response.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
// Helper function to get provider icon and localized name
|
||||
Widget getProviderIcon(String provider, {double size = 24, Color? color}) {
|
||||
@@ -165,9 +168,7 @@ class AccountConnectionNewSheet extends HookConsumerWidget {
|
||||
scopes: [AppleIDAuthorizationScopes.email],
|
||||
webAuthenticationOptions: WebAuthenticationOptions(
|
||||
clientId: 'dev.solsynth.solarpass',
|
||||
redirectUri: Uri.parse(
|
||||
'https://id.solian.app/auth/callback/apple',
|
||||
),
|
||||
redirectUri: Uri.parse('https://id.solian.app/auth/callback'),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -195,17 +196,25 @@ class AccountConnectionNewSheet extends HookConsumerWidget {
|
||||
case 'github':
|
||||
case 'discord':
|
||||
case 'afdian':
|
||||
await Navigator.of(context, rootNavigator: true).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => OidcScreen(
|
||||
provider: selectedProvider.value.toLowerCase(),
|
||||
title:
|
||||
'Connect with ${selectedProvider.value.capitalizeEachWord()}',
|
||||
),
|
||||
),
|
||||
);
|
||||
if (context.mounted) Navigator.pop(context, true);
|
||||
if (kIsWeb) {
|
||||
final serverUrl = ref.watch(serverUrlProvider);
|
||||
final accessToken = ref.watch(tokenProvider);
|
||||
launchUrlString(
|
||||
'$serverUrl/id/auth/login/${selectedProvider.value}?tk=${accessToken!.token}',
|
||||
);
|
||||
} else {
|
||||
await Navigator.of(context, rootNavigator: true).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => OidcScreen(
|
||||
provider: selectedProvider.value.toLowerCase(),
|
||||
title:
|
||||
'Connect with ${selectedProvider.value.capitalizeEachWord()}',
|
||||
),
|
||||
),
|
||||
);
|
||||
if (context.mounted) Navigator.pop(context, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
showSnackBar('accountConnectionAddError'.tr());
|
||||
|
@@ -2,6 +2,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
@@ -16,7 +17,7 @@ import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/services/color.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/services/text.dart';
|
||||
import 'package:island/utils/text.dart';
|
||||
import 'package:island/services/time.dart';
|
||||
import 'package:island/services/timezone/native.dart';
|
||||
import 'package:island/widgets/account/account_name.dart';
|
||||
@@ -297,6 +298,18 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
child: Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
Icon(Symbols.fingerprint, size: 17, fill: 1).padding(right: 2),
|
||||
Text(data.id),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: data.id));
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/widgets/account/account_pfc.dart';
|
||||
import 'package:island/widgets/account/account_picker.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
@@ -99,7 +100,10 @@ class RelationshipListTile extends StatelessWidget {
|
||||
|
||||
return ListTile(
|
||||
contentPadding: const EdgeInsets.only(left: 16, right: 12),
|
||||
leading: ProfilePictureWidget(fileId: account.profile.picture?.id),
|
||||
leading: AccountPfcGestureDetector(
|
||||
uname: account.name,
|
||||
child: ProfilePictureWidget(fileId: account.profile.picture?.id),
|
||||
),
|
||||
title: Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
|
@@ -700,45 +700,48 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onSubmitted: isBusy.value ? null : (_) => performNewTicket(),
|
||||
).padding(horizontal: 7),
|
||||
Row(
|
||||
spacing: 6,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text("loginOr").tr().fontSize(11).opacity(0.85),
|
||||
const Gap(8),
|
||||
Spacer(),
|
||||
IconButton.filledTonal(
|
||||
onPressed: () => withOidc('github'),
|
||||
padding: EdgeInsets.zero,
|
||||
icon: getProviderIcon(
|
||||
"github",
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
if (!kIsWeb)
|
||||
Row(
|
||||
spacing: 6,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text("loginOr").tr().fontSize(11).opacity(0.85),
|
||||
const Gap(8),
|
||||
Spacer(),
|
||||
IconButton.filledTonal(
|
||||
onPressed: () => withOidc('github'),
|
||||
padding: EdgeInsets.zero,
|
||||
icon: getProviderIcon(
|
||||
"github",
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
tooltip: 'GitHub',
|
||||
),
|
||||
tooltip: 'GitHub',
|
||||
),
|
||||
IconButton.filledTonal(
|
||||
onPressed: () => withOidc('google'),
|
||||
padding: EdgeInsets.zero,
|
||||
icon: getProviderIcon(
|
||||
"google",
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
IconButton.filledTonal(
|
||||
onPressed: () => withOidc('google'),
|
||||
padding: EdgeInsets.zero,
|
||||
icon: getProviderIcon(
|
||||
"google",
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
tooltip: 'Google',
|
||||
),
|
||||
tooltip: 'Google',
|
||||
),
|
||||
IconButton.filledTonal(
|
||||
onPressed: withApple,
|
||||
padding: EdgeInsets.zero,
|
||||
icon: getProviderIcon(
|
||||
"apple",
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
IconButton.filledTonal(
|
||||
onPressed: withApple,
|
||||
padding: EdgeInsets.zero,
|
||||
icon: getProviderIcon(
|
||||
"apple",
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
tooltip: 'Apple Account',
|
||||
),
|
||||
tooltip: 'Apple Account',
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 8, vertical: 8),
|
||||
],
|
||||
).padding(horizontal: 8, vertical: 8)
|
||||
else
|
||||
const Gap(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
@@ -4,6 +4,7 @@ import "dart:developer" as developer;
|
||||
import "dart:io";
|
||||
import "package:dio/dio.dart";
|
||||
import "package:easy_localization/easy_localization.dart";
|
||||
import "package:file_picker/file_picker.dart";
|
||||
import "package:flutter/foundation.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:go_router/go_router.dart";
|
||||
@@ -1251,26 +1252,32 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
}, [id]);
|
||||
|
||||
Future<void> pickPhotoMedia() async {
|
||||
final result = await ref
|
||||
.watch(imagePickerProvider)
|
||||
.pickMultiImage(requestFullMetadata: true);
|
||||
if (result.isEmpty) return;
|
||||
final result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.image,
|
||||
allowMultiple: true,
|
||||
allowCompression: false,
|
||||
);
|
||||
if (result == null || result.count == 0) return;
|
||||
attachments.value = [
|
||||
...attachments.value,
|
||||
...result.map(
|
||||
(e) => UniversalFile(data: e, type: UniversalFileType.image),
|
||||
...result.files.map(
|
||||
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.image),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> pickVideoMedia() async {
|
||||
final result = await ref
|
||||
.watch(imagePickerProvider)
|
||||
.pickVideo(source: ImageSource.gallery);
|
||||
if (result == null) return;
|
||||
final result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.video,
|
||||
allowMultiple: true,
|
||||
allowCompression: false,
|
||||
);
|
||||
if (result == null || result.count == 0) return;
|
||||
attachments.value = [
|
||||
...attachments.value,
|
||||
UniversalFile(data: result, type: UniversalFileType.video),
|
||||
...result.files.map(
|
||||
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.video),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1387,6 +1394,8 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
],
|
||||
);
|
||||
|
||||
const messageKeyPrefix = 'message-';
|
||||
|
||||
Widget chatMessageListWidget(List<LocalChatMessage> messageList) =>
|
||||
SuperListView.builder(
|
||||
listController: listController,
|
||||
@@ -1396,7 +1405,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
itemCount: messageList.length,
|
||||
findChildIndexCallback: (key) {
|
||||
final valueKey = key as ValueKey;
|
||||
final messageId = valueKey.value as String;
|
||||
final messageId = (valueKey.value as String).substring(
|
||||
messageKeyPrefix.length,
|
||||
);
|
||||
return messageList.indexWhere((m) => m.id == messageId);
|
||||
},
|
||||
extentEstimation: (_, _) => 40,
|
||||
@@ -1413,10 +1424,13 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
.abs() >
|
||||
3;
|
||||
|
||||
final key = ValueKey('$messageKeyPrefix${message.id}');
|
||||
|
||||
return chatIdentity.when(
|
||||
skipError: true,
|
||||
data:
|
||||
(identity) => MessageItem(
|
||||
key: key,
|
||||
message: message,
|
||||
isCurrentUser: identity?.id == message.senderId,
|
||||
onAction: (action) {
|
||||
@@ -1459,6 +1473,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
),
|
||||
loading:
|
||||
() => MessageItem(
|
||||
key: key,
|
||||
message: message,
|
||||
isCurrentUser: false,
|
||||
onAction: null,
|
||||
@@ -1466,7 +1481,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
showAvatar: false,
|
||||
onJump: (_) {},
|
||||
),
|
||||
error: (_, _) => const SizedBox.shrink(),
|
||||
error: (_, _) => SizedBox.shrink(key: key),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@@ -153,7 +153,9 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('chatBreak5m').tr(),
|
||||
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak5m'.tr()]),
|
||||
subtitle: const Text(
|
||||
'chatBreakHour',
|
||||
).tr(args: ['chatBreak5m'.tr()]),
|
||||
leading: const Icon(Symbols.circle),
|
||||
onTap: () {
|
||||
setChatBreak(now.add(const Duration(minutes: 5)));
|
||||
@@ -165,7 +167,9 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('chatBreak10m').tr(),
|
||||
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak10m'.tr()]),
|
||||
subtitle: const Text(
|
||||
'chatBreakHour',
|
||||
).tr(args: ['chatBreak10m'.tr()]),
|
||||
leading: const Icon(Symbols.circle),
|
||||
onTap: () {
|
||||
setChatBreak(now.add(const Duration(minutes: 10)));
|
||||
@@ -177,7 +181,9 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('chatBreak15m').tr(),
|
||||
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak15m'.tr()]),
|
||||
subtitle: const Text(
|
||||
'chatBreakHour',
|
||||
).tr(args: ['chatBreak15m'.tr()]),
|
||||
leading: const Icon(Symbols.timer_3),
|
||||
onTap: () {
|
||||
setChatBreak(now.add(const Duration(minutes: 15)));
|
||||
@@ -189,7 +195,9 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('chatBreak30m').tr(),
|
||||
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak30m'.tr()]),
|
||||
subtitle: const Text(
|
||||
'chatBreakHour',
|
||||
).tr(args: ['chatBreak30m'.tr()]),
|
||||
leading: const Icon(Symbols.timer),
|
||||
onTap: () {
|
||||
setChatBreak(now.add(const Duration(minutes: 30)));
|
||||
@@ -247,7 +255,10 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
return AppScaffold(
|
||||
body: roomState.when(
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, _) => Center(child: Text('errorGeneric'.tr(args: [error.toString()]))),
|
||||
error:
|
||||
(error, _) => Center(
|
||||
child: Text('errorGeneric'.tr(args: [error.toString()])),
|
||||
),
|
||||
data:
|
||||
(currentRoom) => CustomScrollView(
|
||||
slivers: [
|
||||
@@ -375,12 +386,26 @@ class ChatDetailScreen extends HookConsumerWidget {
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
title: const Text('searchMessages').tr(),
|
||||
subtitle: totalMessages.when(
|
||||
data: (count) => Text('messagesCount'.tr(args: [count.toString()])),
|
||||
loading: () => const CircularProgressIndicator(),
|
||||
error: (err, stack) => Text('errorGeneric'.tr(args: [err.toString()])),
|
||||
data:
|
||||
(count) => Text(
|
||||
'messagesCount'.tr(
|
||||
args: [count.toString()],
|
||||
),
|
||||
),
|
||||
loading:
|
||||
() => const CircularProgressIndicator(),
|
||||
error:
|
||||
(err, stack) => Text(
|
||||
'errorGeneric'.tr(
|
||||
args: [err.toString()],
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
context.pushNamed('searchMessages', pathParameters: {'id': id});
|
||||
context.pushNamed(
|
||||
'searchMessages',
|
||||
pathParameters: {'id': id},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -716,7 +741,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
||||
? 'permissionModerator'
|
||||
: 'permissionMember',
|
||||
).tr(),
|
||||
Text('dotSeparator').bold().padding(horizontal: 6),
|
||||
Text('·').bold().padding(horizontal: 6),
|
||||
Expanded(child: Text("@${member.account.name}")),
|
||||
],
|
||||
),
|
||||
|
@@ -7,7 +7,7 @@ part of 'room_detail.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$totalMessagesCountHash() =>
|
||||
r'a15c03461f25c2d4d39c0926509bf626ae2550a6';
|
||||
r'd55f1507aba2acdce5e468c1c2e15dba7640c571';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@@ -11,7 +11,7 @@ import 'package:island/models/publisher.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/creators/publishers.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/services/text.dart';
|
||||
import 'package:island/utils/text.dart';
|
||||
import 'package:island/widgets/account/account_picker.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
|
@@ -9,6 +9,7 @@ import 'package:island/widgets/poll/poll_feedback.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
|
||||
part 'poll_list.g.dart';
|
||||
|
||||
@@ -86,7 +87,7 @@ class CreatorPollListScreen extends HookConsumerWidget {
|
||||
onPressed: () => _createPoll(context),
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
body: ExtendedRefreshIndicator(
|
||||
onRefresh: () => ref.refresh(pollListNotifierProvider(pubName).future),
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
|
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:island/pods/webfeed.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/empty_state.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
class WebFeedListScreen extends ConsumerWidget {
|
||||
@@ -20,7 +21,10 @@ class WebFeedListScreen extends ConsumerWidget {
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Symbols.add),
|
||||
onPressed: () {
|
||||
context.pushNamed('creatorFeedNew', pathParameters: {'name': pubName});
|
||||
context.pushNamed(
|
||||
'creatorFeedNew',
|
||||
pathParameters: {'name': pubName},
|
||||
);
|
||||
},
|
||||
),
|
||||
body: feedsAsync.when(
|
||||
@@ -32,7 +36,7 @@ class WebFeedListScreen extends ConsumerWidget {
|
||||
description: 'Add a new web feed to get started',
|
||||
);
|
||||
}
|
||||
return RefreshIndicator(
|
||||
return ExtendedRefreshIndicator(
|
||||
onRefresh: () => ref.refresh(webFeedListProvider(pubName).future),
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
@@ -62,7 +66,10 @@ class WebFeedListScreen extends ConsumerWidget {
|
||||
),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
onTap: () {
|
||||
context.pushNamed('creatorFeedEdit', pathParameters: {'name': pubName, 'feedId': feed.id});
|
||||
context.pushNamed(
|
||||
'creatorFeedEdit',
|
||||
pathParameters: {'name': pubName, 'feedId': feed.id},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@@ -9,6 +9,7 @@ import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
|
||||
part 'bots.g.dart';
|
||||
|
||||
@@ -60,7 +61,7 @@ class BotsScreen extends HookConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
return RefreshIndicator(
|
||||
return ExtendedRefreshIndicator(
|
||||
onRefresh:
|
||||
() => ref.refresh(botsProvider(publisherName, projectId).future),
|
||||
child: ListView.builder(
|
||||
|
@@ -27,6 +27,7 @@ import 'package:island/pods/network.dart';
|
||||
import 'package:island/widgets/realm/realm_card.dart';
|
||||
import 'package:island/widgets/publisher/publisher_card.dart';
|
||||
import 'package:island/widgets/web_article_card.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'explore.g.dart';
|
||||
@@ -368,7 +369,7 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
|
||||
final isWide = isWideScreen(context);
|
||||
|
||||
return RefreshIndicator(
|
||||
return ExtendedRefreshIndicator(
|
||||
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
|
||||
child: PagingHelperView(
|
||||
provider: activityListNotifierProvider(filter),
|
||||
@@ -399,6 +400,69 @@ class _DiscoveryActivityItem extends StatelessWidget {
|
||||
final items = data['items'] as List;
|
||||
final type = items.firstOrNull?['type'] ?? 'unknown';
|
||||
|
||||
var flexWeights = isWideScreen(context) ? <int>[3, 2, 1] : <int>[4, 1];
|
||||
if (type == 'post') flexWeights = <int>[3, 2];
|
||||
|
||||
final height = type == 'post' ? 280.0 : 180.0;
|
||||
|
||||
final contentWidget = switch (type) {
|
||||
'post' => ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: items.length,
|
||||
separatorBuilder: (context, index) => const Gap(12),
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
itemBuilder: (context, index) {
|
||||
final item = items[index];
|
||||
return Container(
|
||||
width: 320,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 1 / MediaQuery.of(context).devicePixelRatio,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.5),
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: SingleChildScrollView(
|
||||
child: PostActionableItem(
|
||||
item: SnPost.fromJson(item['data']),
|
||||
isCompact: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
_ => CarouselView.weighted(
|
||||
flexWeights: flexWeights,
|
||||
consumeMaxWeight: false,
|
||||
enableSplash: false,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
itemSnapping: false,
|
||||
children: [
|
||||
for (final item in items)
|
||||
switch (type) {
|
||||
'realm' => RealmCard(
|
||||
realm: SnRealm.fromJson(item['data']),
|
||||
maxWidth: 280,
|
||||
),
|
||||
'publisher' => PublisherCard(
|
||||
publisher: SnPublisher.fromJson(item['data']),
|
||||
maxWidth: 280,
|
||||
),
|
||||
'article' => WebArticleCard(
|
||||
article: SnWebArticle.fromJson(item['data']),
|
||||
maxWidth: 280,
|
||||
),
|
||||
_ => const Placeholder(),
|
||||
},
|
||||
],
|
||||
),
|
||||
};
|
||||
|
||||
return Card(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Column(
|
||||
@@ -407,13 +471,20 @@ class _DiscoveryActivityItem extends StatelessWidget {
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Symbols.explore, size: 19),
|
||||
Icon(switch (type) {
|
||||
'realm' => Symbols.public,
|
||||
'publisher' => Symbols.account_circle,
|
||||
'article' => Symbols.auto_stories,
|
||||
'post' => Symbols.shuffle,
|
||||
_ => Symbols.explore,
|
||||
}, size: 19),
|
||||
const Gap(8),
|
||||
Text(
|
||||
(switch (type) {
|
||||
'realm' => 'discoverRealms',
|
||||
'publisher' => 'discoverPublishers',
|
||||
'article' => 'discoverWebArticles',
|
||||
'post' => 'discoverShuffledPost',
|
||||
_ => 'unknown',
|
||||
}).tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
@@ -421,37 +492,8 @@ class _DiscoveryActivityItem extends StatelessWidget {
|
||||
],
|
||||
).padding(horizontal: 20, top: 8, bottom: 4),
|
||||
SizedBox(
|
||||
height: 180,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 200),
|
||||
child: CarouselView.weighted(
|
||||
flexWeights:
|
||||
isWideScreen(context) ? <int>[3, 2, 1] : <int>[4, 1],
|
||||
consumeMaxWeight: false,
|
||||
enableSplash: false,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
children: [
|
||||
for (final item in items)
|
||||
switch (type) {
|
||||
'realm' => RealmCard(
|
||||
realm: SnRealm.fromJson(item['data']),
|
||||
maxWidth: 280,
|
||||
),
|
||||
'publisher' => PublisherCard(
|
||||
publisher: SnPublisher.fromJson(item['data']),
|
||||
maxWidth: 280,
|
||||
),
|
||||
'article' => WebArticleCard(
|
||||
article: SnWebArticle.fromJson(item['data']),
|
||||
maxWidth: 280,
|
||||
),
|
||||
_ => Placeholder(),
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
height: height,
|
||||
child: contentWidget,
|
||||
).padding(bottom: 8, horizontal: 8),
|
||||
],
|
||||
),
|
||||
@@ -569,7 +611,8 @@ class ActivityListNotifier extends _$ActivityListNotifier
|
||||
if (cursor != null) 'cursor': cursor,
|
||||
'take': take,
|
||||
if (filter != null) 'filter': filter,
|
||||
if (kDebugMode) 'debugInclude': 'realms,publishers,articles',
|
||||
if (kDebugMode)
|
||||
'debugInclude': 'realms,publishers,articles,shuffledPosts',
|
||||
};
|
||||
|
||||
final response = await client.get(
|
||||
@@ -584,12 +627,13 @@ class ActivityListNotifier extends _$ActivityListNotifier
|
||||
|
||||
final hasMore = (items.firstOrNull?.type ?? 'empty') != 'empty';
|
||||
final nextCursor =
|
||||
items
|
||||
.map((x) => x.createdAt)
|
||||
.lastOrNull
|
||||
?.toUtc()
|
||||
.toIso8601String()
|
||||
.toString();
|
||||
items.isNotEmpty
|
||||
? items
|
||||
.map((x) => x.createdAt)
|
||||
.reduce((a, b) => a.isBefore(b) ? a : b)
|
||||
.toUtc()
|
||||
.toIso8601String()
|
||||
: null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: items,
|
||||
|
@@ -7,7 +7,7 @@ part of 'explore.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$activityListNotifierHash() =>
|
||||
r'b75fd5c08d5f84ca433e16b7387d317ea72b91c9';
|
||||
r'a4968856ac34b59d47cfd4a7cbb39289aef2a1b1';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@@ -1,5 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
@@ -7,6 +9,7 @@ import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/post/post_item.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
final postSearchNotifierProvider = StateNotifierProvider.autoDispose<
|
||||
PostSearchNotifier,
|
||||
@@ -18,6 +21,13 @@ class PostSearchNotifier
|
||||
final AutoDisposeRef ref;
|
||||
static const int _pageSize = 20;
|
||||
String _currentQuery = '';
|
||||
String? _pubName;
|
||||
String? _realm;
|
||||
int? _type;
|
||||
List<String>? _categories;
|
||||
List<String>? _tags;
|
||||
bool _shuffle = false;
|
||||
bool? _pinned;
|
||||
bool _isLoading = false;
|
||||
|
||||
PostSearchNotifier(this.ref) : super(const AsyncValue.loading()) {
|
||||
@@ -26,11 +36,38 @@ class PostSearchNotifier
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> search(String query) async {
|
||||
Future<void> search(
|
||||
String query, {
|
||||
String? pubName,
|
||||
String? realm,
|
||||
int? type,
|
||||
List<String>? categories,
|
||||
List<String>? tags,
|
||||
bool shuffle = false,
|
||||
bool? pinned,
|
||||
}) async {
|
||||
if (_isLoading) return;
|
||||
|
||||
_currentQuery = query.trim();
|
||||
if (_currentQuery.isEmpty) {
|
||||
_pubName = pubName;
|
||||
_realm = realm;
|
||||
_type = type;
|
||||
_categories = categories;
|
||||
_tags = tags;
|
||||
_shuffle = shuffle;
|
||||
_pinned = pinned;
|
||||
|
||||
// Allow search even with empty query if any filters are applied
|
||||
final hasFilters =
|
||||
pubName != null ||
|
||||
realm != null ||
|
||||
type != null ||
|
||||
categories != null ||
|
||||
tags != null ||
|
||||
shuffle ||
|
||||
pinned != null;
|
||||
|
||||
if (_currentQuery.isEmpty && !hasFilters) {
|
||||
state = AsyncValue.data(
|
||||
CursorPagingData(items: [], hasMore: false, nextCursor: null),
|
||||
);
|
||||
@@ -57,6 +94,13 @@ class PostSearchNotifier
|
||||
'offset': offset,
|
||||
'take': _pageSize,
|
||||
'vector': false,
|
||||
if (_pubName != null) 'pub': _pubName,
|
||||
if (_realm != null) 'realm': _realm,
|
||||
if (_type != null) 'type': _type,
|
||||
if (_tags != null) 'tags': _tags,
|
||||
if (_categories != null) 'categories': _categories,
|
||||
if (_shuffle) 'shuffle': true,
|
||||
if (_pinned != null) 'pinned': _pinned,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -80,100 +124,269 @@ class PostSearchNotifier
|
||||
}
|
||||
}
|
||||
|
||||
class PostSearchScreen extends ConsumerStatefulWidget {
|
||||
class PostSearchScreen extends HookConsumerWidget {
|
||||
const PostSearchScreen({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<PostSearchScreen> createState() => _PostSearchScreenState();
|
||||
}
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final searchController = useTextEditingController();
|
||||
final debounce = useMemoized(() => Duration(milliseconds: 500));
|
||||
final debounceTimer = useRef<Timer?>(null);
|
||||
final showFilters = useState(false);
|
||||
final pubNameController = useTextEditingController();
|
||||
final realmController = useTextEditingController();
|
||||
final typeValue = useState<int?>(null);
|
||||
final selectedCategories = useState<List<String>>([]);
|
||||
final selectedTags = useState<List<String>>([]);
|
||||
final shuffleValue = useState(false);
|
||||
final pinnedValue = useState<bool?>(null);
|
||||
|
||||
class _PostSearchScreenState extends ConsumerState<PostSearchScreen> {
|
||||
final _searchController = TextEditingController();
|
||||
final _debounce = Duration(milliseconds: 500);
|
||||
Timer? _debounceTimer;
|
||||
useEffect(() {
|
||||
return () {
|
||||
searchController.dispose();
|
||||
pubNameController.dispose();
|
||||
realmController.dispose();
|
||||
debounceTimer.value?.cancel();
|
||||
};
|
||||
}, []);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
_debounceTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
void onSearchChanged(String query) {
|
||||
if (debounceTimer.value?.isActive ?? false) debounceTimer.value!.cancel();
|
||||
|
||||
void _onSearchChanged(String query) {
|
||||
if (_debounceTimer?.isActive ?? false) _debounceTimer!.cancel();
|
||||
debounceTimer.value = Timer(debounce, () {
|
||||
ref.read(postSearchNotifierProvider.notifier).search(query);
|
||||
});
|
||||
}
|
||||
|
||||
_debounceTimer = Timer(_debounce, () {
|
||||
ref.read(postSearchNotifierProvider.notifier).search(query);
|
||||
});
|
||||
}
|
||||
void onSearchWithFilters(String query) {
|
||||
if (debounceTimer.value?.isActive ?? false) debounceTimer.value!.cancel();
|
||||
|
||||
debounceTimer.value = Timer(debounce, () {
|
||||
ref
|
||||
.read(postSearchNotifierProvider.notifier)
|
||||
.search(
|
||||
query,
|
||||
pubName:
|
||||
pubNameController.text.isNotEmpty
|
||||
? pubNameController.text
|
||||
: null,
|
||||
realm:
|
||||
realmController.text.isNotEmpty ? realmController.text : null,
|
||||
type: typeValue.value,
|
||||
categories:
|
||||
selectedCategories.value.isNotEmpty
|
||||
? selectedCategories.value
|
||||
: null,
|
||||
tags: selectedTags.value.isNotEmpty ? selectedTags.value : null,
|
||||
shuffle: shuffleValue.value,
|
||||
pinned: pinnedValue.value,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void toggleFilters() {
|
||||
showFilters.value = !showFilters.value;
|
||||
}
|
||||
|
||||
void applyFilters() {
|
||||
onSearchWithFilters(searchController.text);
|
||||
}
|
||||
|
||||
void clearFilters() {
|
||||
pubNameController.clear();
|
||||
realmController.clear();
|
||||
typeValue.value = null;
|
||||
selectedCategories.value = [];
|
||||
selectedTags.value = [];
|
||||
shuffleValue.value = false;
|
||||
pinnedValue.value = null;
|
||||
onSearchChanged(searchController.text);
|
||||
}
|
||||
|
||||
Widget buildFilterPanel() {
|
||||
return Card(
|
||||
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'filters'.tr(),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
).padding(left: 4),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: applyFilters,
|
||||
child: Text('apply'.tr()),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: clearFilters,
|
||||
child: Text('clear'.tr()),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: pubNameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'pubName'.tr(),
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
onChanged:
|
||||
(value) => onSearchWithFilters(searchController.text),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: realmController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'realm'.tr(),
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
onChanged:
|
||||
(value) => onSearchWithFilters(searchController.text),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: shuffleValue.value,
|
||||
onChanged: (value) {
|
||||
shuffleValue.value = value ?? false;
|
||||
onSearchWithFilters(searchController.text);
|
||||
},
|
||||
),
|
||||
Text('shuffle'.tr()),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: pinnedValue.value ?? false,
|
||||
onChanged: (value) {
|
||||
pinnedValue.value = value;
|
||||
onSearchWithFilters(searchController.text);
|
||||
},
|
||||
),
|
||||
Text('pinned'.tr()),
|
||||
],
|
||||
),
|
||||
// TODO: Add dropdown for type selection
|
||||
// TODO: Add multi-select for categories and tags
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
appBar: AppBar(
|
||||
title: TextField(
|
||||
controller: _searchController,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search posts...',
|
||||
border: InputBorder.none,
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor,
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'search'.tr(),
|
||||
border: InputBorder.none,
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor,
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor,
|
||||
),
|
||||
onChanged: onSearchChanged,
|
||||
onSubmitted: (value) {
|
||||
onSearchWithFilters(value);
|
||||
},
|
||||
autofocus: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor,
|
||||
),
|
||||
onChanged: _onSearchChanged,
|
||||
onSubmitted: (value) {
|
||||
ref.read(postSearchNotifierProvider.notifier).search(value);
|
||||
},
|
||||
autofocus: true,
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
showFilters.value
|
||||
? Icons.filter_alt
|
||||
: Icons.filter_alt_outlined,
|
||||
),
|
||||
onPressed: toggleFilters,
|
||||
tooltip: 'toggleFilters'.tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final searchState = ref.watch(postSearchNotifierProvider);
|
||||
|
||||
return searchState.when(
|
||||
data: (data) {
|
||||
if (data.items.isEmpty && _searchController.text.isNotEmpty) {
|
||||
return const Center(child: Text('No results found'));
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: data.items.length + (data.hasMore ? 1 : 0),
|
||||
itemBuilder: (context, index) {
|
||||
if (index >= data.items.length) {
|
||||
ref
|
||||
.read(postSearchNotifierProvider.notifier)
|
||||
.fetch(cursor: data.nextCursor);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
if (showFilters.value)
|
||||
SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: buildFilterPanel(),
|
||||
),
|
||||
),
|
||||
),
|
||||
searchState.when(
|
||||
data: (data) {
|
||||
if (data.items.isEmpty && searchController.text.isNotEmpty) {
|
||||
return SliverFillRemaining(
|
||||
child: Center(child: Text('noResultsFound'.tr())),
|
||||
);
|
||||
}
|
||||
|
||||
final post = data.items[index];
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 600),
|
||||
child: Card(
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate((context, index) {
|
||||
if (index >= data.items.length) {
|
||||
ref
|
||||
.read(postSearchNotifierProvider.notifier)
|
||||
.fetch(cursor: data.nextCursor);
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
final post = data.items[index];
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 600),
|
||||
child: Card(
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
child: PostActionableItem(
|
||||
item: post,
|
||||
borderRadius: 8,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: PostActionableItem(item: post, borderRadius: 8),
|
||||
),
|
||||
),
|
||||
);
|
||||
}, childCount: data.items.length + (data.hasMore ? 1 : 0)),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error:
|
||||
(error, stack) => ResponseErrorWidget(
|
||||
error: error,
|
||||
onRetry: () => ref.invalidate(postSearchNotifierProvider),
|
||||
),
|
||||
loading:
|
||||
() => SliverFillRemaining(
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
error:
|
||||
(error, stack) => SliverFillRemaining(
|
||||
child: ResponseErrorWidget(
|
||||
error: error,
|
||||
onRetry:
|
||||
() => ref.invalidate(postSearchNotifierProvider),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@@ -23,6 +23,7 @@ import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:island/widgets/realm/realm_list_tile.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
|
||||
part 'realms.g.dart';
|
||||
|
||||
@@ -90,7 +91,7 @@ class RealmListScreen extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
floatingActionButtonLocation: TabbedFabLocation(context),
|
||||
body: RefreshIndicator(
|
||||
body: ExtendedRefreshIndicator(
|
||||
child: realms.when(
|
||||
data:
|
||||
(value) => Column(
|
||||
|
@@ -219,6 +219,33 @@ class SettingsScreen extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
|
||||
// Background image enabled
|
||||
if (!kIsWeb && docBasepath.value != null)
|
||||
FutureBuilder<bool>(
|
||||
future:
|
||||
File('${docBasepath.value}/$kAppBackgroundImagePath').exists(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || !snapshot.data!) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
minLeadingWidth: 48,
|
||||
title: Text('settingsBackgroundImageEnable').tr(),
|
||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||
leading: const Icon(Symbols.image),
|
||||
trailing: Switch(
|
||||
value: settings.showBackgroundImage,
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(appSettingsNotifierProvider.notifier)
|
||||
.setShowBackgroundImage(value);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
// Clear background image option
|
||||
if (!kIsWeb && docBasepath.value != null)
|
||||
FutureBuilder<bool>(
|
||||
@@ -426,63 +453,8 @@ class SettingsScreen extends HookConsumerWidget {
|
||||
];
|
||||
|
||||
// Desktop-specific settings
|
||||
final desktopSettings =
|
||||
!isDesktop
|
||||
? <Widget>[]
|
||||
: <Widget>[
|
||||
ListTile(
|
||||
minLeadingWidth: 48,
|
||||
title: Text('settingsKeyboardShortcuts').tr(),
|
||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||
leading: const Icon(Symbols.keyboard),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: Text('settingsKeyboardShortcuts').tr(),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_ShortcutRow(
|
||||
shortcut: 'Ctrl+F',
|
||||
description:
|
||||
'settingsKeyboardShortcutSearch'.tr(),
|
||||
),
|
||||
_ShortcutRow(
|
||||
shortcut: 'Ctrl+,',
|
||||
description:
|
||||
'settingsKeyboardShortcutSettings'.tr(),
|
||||
),
|
||||
_ShortcutRow(
|
||||
shortcut: 'Ctrl+N',
|
||||
description:
|
||||
'settingsKeyboardShortcutNewMessage'.tr(),
|
||||
),
|
||||
_ShortcutRow(
|
||||
shortcut: 'Esc',
|
||||
description:
|
||||
'settingsKeyboardShortcutCloseDialog'
|
||||
.tr(),
|
||||
),
|
||||
// Add more shortcuts as needed
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('close').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
),
|
||||
];
|
||||
// But nothing for now
|
||||
final desktopSettings = !isDesktop ? <Widget>[] : <Widget>[];
|
||||
|
||||
// Create a responsive layout based on screen width
|
||||
Widget buildSettingsList() {
|
||||
@@ -553,34 +525,7 @@ class SettingsScreen extends HookConsumerWidget {
|
||||
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
appBar: AppBar(
|
||||
title: Text('settings').tr(),
|
||||
actions:
|
||||
isDesktop
|
||||
? [
|
||||
IconButton(
|
||||
icon: const Icon(Symbols.help_outline),
|
||||
onPressed: () {
|
||||
// Show help dialog
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: Text('settingsHelp').tr(),
|
||||
content: Text('settingsHelpContent').tr(),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('close').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
appBar: AppBar(title: Text('settings').tr()),
|
||||
body: Focus(
|
||||
autofocus: true,
|
||||
onKeyEvent: (node, event) {
|
||||
@@ -630,35 +575,3 @@ class _SettingsSection extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper widget for displaying keyboard shortcuts
|
||||
class _ShortcutRow extends StatelessWidget {
|
||||
final String shortcut;
|
||||
final String description;
|
||||
|
||||
const _ShortcutRow({required this.shortcut, required this.description});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
child: Text(shortcut, style: TextStyle(fontFamily: 'monospace')),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Text(description),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
58
lib/screens/tray_manager.dart
Normal file
58
lib/screens/tray_manager.dart
Normal file
@@ -0,0 +1,58 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:tray_manager/tray_manager.dart';
|
||||
|
||||
class TrayService {
|
||||
TrayService._();
|
||||
|
||||
static final TrayService _instance = TrayService._();
|
||||
|
||||
static TrayService get instance => _instance;
|
||||
|
||||
bool _checkPlatformAvalability() {
|
||||
if (kIsWeb) return false;
|
||||
if (Platform.isAndroid || Platform.isIOS) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> initialize(TrayListener listener) async {
|
||||
if (!_checkPlatformAvalability()) return;
|
||||
|
||||
await trayManager.setIcon(
|
||||
Platform.isWindows
|
||||
? 'assets/icons/icon.ico'
|
||||
: 'assets/icons/icon-outline.svg',
|
||||
);
|
||||
|
||||
final menu = Menu(
|
||||
items: [
|
||||
MenuItem(key: 'show_window', label: 'Show Window'),
|
||||
MenuItem.separator(),
|
||||
MenuItem(key: 'exit_app', label: 'Exit App'),
|
||||
],
|
||||
);
|
||||
await trayManager.setContextMenu(menu);
|
||||
|
||||
trayManager.addListener(listener);
|
||||
}
|
||||
|
||||
Future<void> dispose(TrayListener listener) async {
|
||||
if (!_checkPlatformAvalability()) return;
|
||||
|
||||
trayManager.removeListener(listener);
|
||||
await trayManager.destroy();
|
||||
}
|
||||
|
||||
void handleAction(MenuItem item) {
|
||||
switch (item.key) {
|
||||
case 'show_window':
|
||||
appWindow.show();
|
||||
break;
|
||||
case 'exit_app':
|
||||
appWindow.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,6 +6,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:island/main.dart';
|
||||
@@ -16,54 +17,159 @@ import 'package:island/widgets/app_notification.dart';
|
||||
import 'package:top_snackbar_flutter/top_snack_bar.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
AppLifecycleState _appLifecycleState = AppLifecycleState.resumed;
|
||||
|
||||
void _onAppLifecycleChanged(AppLifecycleState state) {
|
||||
_appLifecycleState = state;
|
||||
}
|
||||
|
||||
Future<void> initializeLocalNotifications() async {
|
||||
const AndroidInitializationSettings initializationSettingsAndroid =
|
||||
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
|
||||
const DarwinInitializationSettings initializationSettingsIOS =
|
||||
DarwinInitializationSettings();
|
||||
|
||||
const DarwinInitializationSettings initializationSettingsMacOS =
|
||||
DarwinInitializationSettings();
|
||||
|
||||
const LinuxInitializationSettings initializationSettingsLinux =
|
||||
LinuxInitializationSettings(defaultActionName: 'Open notification');
|
||||
|
||||
const WindowsInitializationSettings initializationSettingsWindows =
|
||||
WindowsInitializationSettings(
|
||||
appName: 'Island',
|
||||
appUserModelId: 'dev.solsynth.solian',
|
||||
guid: 'dev.solsynth.solian',
|
||||
);
|
||||
|
||||
const InitializationSettings initializationSettings = InitializationSettings(
|
||||
android: initializationSettingsAndroid,
|
||||
iOS: initializationSettingsIOS,
|
||||
macOS: initializationSettingsMacOS,
|
||||
linux: initializationSettingsLinux,
|
||||
windows: initializationSettingsWindows,
|
||||
);
|
||||
|
||||
await flutterLocalNotificationsPlugin.initialize(
|
||||
initializationSettings,
|
||||
onDidReceiveNotificationResponse: (NotificationResponse response) async {
|
||||
final payload = response.payload;
|
||||
if (payload != null) {
|
||||
if (payload.startsWith('/')) {
|
||||
// In-app routes
|
||||
rootNavigatorKey.currentContext?.push(payload);
|
||||
} else {
|
||||
// External URLs
|
||||
launchUrlString(payload);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
WidgetsBinding.instance.addObserver(
|
||||
LifecycleEventHandler(onAppLifecycleChanged: _onAppLifecycleChanged),
|
||||
);
|
||||
}
|
||||
|
||||
class LifecycleEventHandler extends WidgetsBindingObserver {
|
||||
final void Function(AppLifecycleState) onAppLifecycleChanged;
|
||||
|
||||
LifecycleEventHandler({required this.onAppLifecycleChanged});
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
onAppLifecycleChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
StreamSubscription<WebSocketPacket> setupNotificationListener(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
) {
|
||||
final ws = ref.watch(websocketProvider);
|
||||
return ws.dataStream.listen((pkt) {
|
||||
return ws.dataStream.listen((pkt) async {
|
||||
if (pkt.type == "notifications.new") {
|
||||
final notification = SnNotification.fromJson(pkt.data!);
|
||||
showTopSnackBar(
|
||||
globalOverlay.currentState!,
|
||||
Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: NotificationCard(notification: notification),
|
||||
if (_appLifecycleState == AppLifecycleState.resumed) {
|
||||
// App is focused, show in-app notification
|
||||
log(
|
||||
'[Notification] Showing in-app notification: ${notification.title}',
|
||||
);
|
||||
showTopSnackBar(
|
||||
globalOverlay.currentState!,
|
||||
Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: NotificationCard(notification: notification),
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (notification.meta['action_uri'] != null) {
|
||||
var uri = notification.meta['action_uri'] as String;
|
||||
if (uri.startsWith('/')) {
|
||||
// In-app routes
|
||||
rootNavigatorKey.currentContext?.push(
|
||||
notification.meta['action_uri'],
|
||||
);
|
||||
} else {
|
||||
// External URLs
|
||||
launchUrlString(uri);
|
||||
onTap: () {
|
||||
if (notification.meta['action_uri'] != null) {
|
||||
var uri = notification.meta['action_uri'] as String;
|
||||
if (uri.startsWith('/')) {
|
||||
// In-app routes
|
||||
rootNavigatorKey.currentContext?.push(
|
||||
notification.meta['action_uri'],
|
||||
);
|
||||
} else {
|
||||
// External URLs
|
||||
launchUrlString(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissed: () {},
|
||||
dismissType: DismissType.onSwipe,
|
||||
displayDuration: const Duration(seconds: 5),
|
||||
snackBarPosition: SnackBarPosition.top,
|
||||
padding: EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top:
|
||||
(!kIsWeb &&
|
||||
(Platform.isMacOS ||
|
||||
Platform.isWindows ||
|
||||
Platform.isLinux))
|
||||
? 28
|
||||
// ignore: use_build_context_synchronously
|
||||
: MediaQuery.of(context).padding.top + 16,
|
||||
bottom: 16,
|
||||
),
|
||||
);
|
||||
},
|
||||
onDismissed: () {},
|
||||
dismissType: DismissType.onSwipe,
|
||||
displayDuration: const Duration(seconds: 5),
|
||||
snackBarPosition: SnackBarPosition.top,
|
||||
padding: EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top:
|
||||
(!kIsWeb &&
|
||||
(Platform.isMacOS ||
|
||||
Platform.isWindows ||
|
||||
Platform.isLinux))
|
||||
? 28
|
||||
// ignore: use_build_context_synchronously
|
||||
: MediaQuery.of(context).padding.top + 16,
|
||||
bottom: 16,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// App is in background, show system notification (only on supported platforms)
|
||||
if (!kIsWeb && !Platform.isIOS) {
|
||||
log(
|
||||
'[Notification] Showing system notification: ${notification.title}',
|
||||
);
|
||||
const AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails(
|
||||
'channel_id',
|
||||
'channel_name',
|
||||
channelDescription: 'channel_description',
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
ticker: 'ticker',
|
||||
);
|
||||
const NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails,
|
||||
);
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
0,
|
||||
notification.title,
|
||||
notification.content,
|
||||
notificationDetails,
|
||||
payload: notification.meta['action_uri'] as String?,
|
||||
);
|
||||
} else {
|
||||
log(
|
||||
'[Notification] Skipping system notification for unsupported platform: ${notification.title}',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -72,7 +178,7 @@ Future<void> subscribePushNotification(
|
||||
Dio apiClient, {
|
||||
bool detailedErrors = false,
|
||||
}) async {
|
||||
if (Platform.isLinux) {
|
||||
if (!kIsWeb && Platform.isLinux) {
|
||||
return;
|
||||
}
|
||||
await FirebaseMessaging.instance.requestPermission(
|
||||
|
@@ -1,5 +1,11 @@
|
||||
import 'package:flutter_udid/flutter_udid.dart';
|
||||
|
||||
String? _cachedUdid;
|
||||
|
||||
Future<String> getUdid() async {
|
||||
return await FlutterUdid.consistentUdid;
|
||||
if (_cachedUdid != null) {
|
||||
return _cachedUdid!;
|
||||
}
|
||||
_cachedUdid = await FlutterUdid.consistentUdid;
|
||||
return _cachedUdid!;
|
||||
}
|
||||
|
9
lib/utils/format.dart
Normal file
9
lib/utils/format.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
String formatFileSize(int bytes) {
|
||||
if (bytes <= 0) return '0 B';
|
||||
if (bytes < 1024) return '$bytes B';
|
||||
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB';
|
||||
if (bytes < 1024 * 1024 * 1024) {
|
||||
return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB';
|
||||
}
|
||||
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB';
|
||||
}
|
@@ -12,6 +12,7 @@ import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
|
||||
part 'account_devices.g.dart';
|
||||
|
||||
@@ -177,7 +178,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
||||
titleText: 'authSessions'.tr(),
|
||||
child: authDevices.when(
|
||||
data:
|
||||
(data) => RefreshIndicator(
|
||||
(data) => ExtendedRefreshIndicator(
|
||||
onRefresh:
|
||||
() => Future.sync(() => ref.invalidate(authDevicesProvider)),
|
||||
child: ListView.builder(
|
||||
|
@@ -37,7 +37,14 @@ class AccountName extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 4,
|
||||
children: [
|
||||
Flexible(child: Text(account.nick, style: nameStyle)),
|
||||
Flexible(
|
||||
child: Text(
|
||||
account.nick,
|
||||
style: nameStyle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (account.perkSubscription != null)
|
||||
StellarMembershipMark(membership: account.perkSubscription!),
|
||||
if (account.profile.verification != null)
|
||||
@@ -162,7 +169,7 @@ class VerificationStatusCard extends StatelessWidget {
|
||||
size: 32,
|
||||
color: kVerificationMarkColors[mark.type],
|
||||
fill: 1,
|
||||
),
|
||||
).alignment(Alignment.centerLeft),
|
||||
const Gap(8),
|
||||
Text(mark.title ?? 'No title').bold(),
|
||||
Text(mark.description ?? 'descriptionNone'.tr()),
|
||||
|
@@ -111,26 +111,39 @@ class AccountProfileCard extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
if (data.profile.timeZone.isNotEmpty && !kIsWeb)
|
||||
Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.alarm,
|
||||
size: 17,
|
||||
fill: 1,
|
||||
).padding(right: 2),
|
||||
Text(
|
||||
getTzInfo(
|
||||
data.profile.timeZone,
|
||||
).$2.formatCustomGlobal('HH:mm'),
|
||||
).fontSize(12),
|
||||
Text(
|
||||
getTzInfo(
|
||||
data.profile.timeZone,
|
||||
).$1.formatOffsetLocal(),
|
||||
).fontSize(12),
|
||||
],
|
||||
).padding(top: 2),
|
||||
() {
|
||||
try {
|
||||
final tzInfo = getTzInfo(data.profile.timeZone);
|
||||
return Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.alarm,
|
||||
size: 17,
|
||||
fill: 1,
|
||||
).padding(right: 2),
|
||||
Text(
|
||||
tzInfo.$2.formatCustomGlobal('HH:mm'),
|
||||
).fontSize(12),
|
||||
Text(
|
||||
tzInfo.$1.formatOffsetLocal(),
|
||||
).fontSize(12),
|
||||
],
|
||||
).padding(top: 2);
|
||||
} catch (e) {
|
||||
return Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.alarm,
|
||||
size: 17,
|
||||
fill: 1,
|
||||
).padding(right: 2),
|
||||
Text('timezoneNotFound'.tr()).fontSize(12),
|
||||
],
|
||||
).padding(top: 2);
|
||||
}
|
||||
}(),
|
||||
if (data.badges.isNotEmpty)
|
||||
BadgeList(badges: data.badges).padding(top: 12),
|
||||
LevelingProgressCard(
|
||||
|
@@ -60,7 +60,9 @@ class AccountStatusCreationWidget extends HookConsumerWidget {
|
||||
spacing: 4,
|
||||
children: [
|
||||
Icon(Symbols.keyboard_arrow_up),
|
||||
Text('statusCreateHint').tr(),
|
||||
Expanded(
|
||||
child: Text('statusCreateHint', maxLines: 1).tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
).opacity(0.85),
|
||||
|
@@ -17,8 +17,8 @@ class NotificationCard extends HookConsumerWidget {
|
||||
return Card(
|
||||
elevation: 4,
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(bottom: Radius.circular(8)),
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@@ -3,6 +3,7 @@ import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -153,7 +154,7 @@ class _WindowSizeObserver extends WidgetsBindingObserver {
|
||||
|
||||
final rootScaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
class AppScaffold extends StatelessWidget {
|
||||
class AppScaffold extends HookConsumerWidget {
|
||||
final Widget? body;
|
||||
final PreferredSizeWidget? bottomNavigationBar;
|
||||
final PreferredSizeWidget? bottomSheet;
|
||||
@@ -186,7 +187,14 @@ class AppScaffold extends StatelessWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final focusNode = useFocusNode();
|
||||
|
||||
useEffect(() {
|
||||
focusNode.requestFocus();
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
final appBarHeight = appBar?.preferredSize.height ?? 0;
|
||||
final safeTop = MediaQuery.of(context).padding.top;
|
||||
|
||||
@@ -201,29 +209,59 @@ class AppScaffold extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
extendBody: extendBody ?? true,
|
||||
extendBodyBehindAppBar: true,
|
||||
backgroundColor:
|
||||
noBackground
|
||||
? Colors.transparent
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
body:
|
||||
noBackground ? content : AppBackground(isRoot: true, child: content),
|
||||
appBar: appBar,
|
||||
bottomNavigationBar: bottomNavigationBar,
|
||||
bottomSheet: bottomSheet,
|
||||
drawer: drawer,
|
||||
endDrawer: endDrawer,
|
||||
floatingActionButton: floatingActionButton,
|
||||
floatingActionButtonAnimator: floatingActionButtonAnimator,
|
||||
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||
onDrawerChanged: onDrawerChanged,
|
||||
onEndDrawerChanged: onEndDrawerChanged,
|
||||
return Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
LogicalKeySet(LogicalKeyboardKey.escape): const PopIntent(),
|
||||
},
|
||||
child: Actions(
|
||||
actions: <Type, Action<Intent>>{PopIntent: PopAction(context)},
|
||||
child: Focus(
|
||||
focusNode: focusNode,
|
||||
child: Scaffold(
|
||||
extendBody: extendBody ?? true,
|
||||
extendBodyBehindAppBar: true,
|
||||
backgroundColor:
|
||||
noBackground
|
||||
? Colors.transparent
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
body:
|
||||
noBackground
|
||||
? content
|
||||
: AppBackground(isRoot: true, child: content),
|
||||
appBar: appBar,
|
||||
bottomNavigationBar: bottomNavigationBar,
|
||||
bottomSheet: bottomSheet,
|
||||
drawer: drawer,
|
||||
endDrawer: endDrawer,
|
||||
floatingActionButton: floatingActionButton,
|
||||
floatingActionButtonAnimator: floatingActionButtonAnimator,
|
||||
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||
onDrawerChanged: onDrawerChanged,
|
||||
onEndDrawerChanged: onEndDrawerChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PopIntent extends Intent {
|
||||
const PopIntent();
|
||||
}
|
||||
|
||||
class PopAction extends Action<PopIntent> {
|
||||
final BuildContext context;
|
||||
|
||||
PopAction(this.context);
|
||||
|
||||
@override
|
||||
void invoke(PopIntent intent) {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PageBackButton extends StatelessWidget {
|
||||
final Color? color;
|
||||
final List<Shadow>? shadows;
|
||||
@@ -271,11 +309,12 @@ class AppBackground extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final imageFileAsync = ref.watch(backgroundImageFileProvider);
|
||||
final settings = ref.watch(appSettingsNotifierProvider);
|
||||
|
||||
if (isRoot || !isWideScreen(context)) {
|
||||
return imageFileAsync.when(
|
||||
data: (file) {
|
||||
if (file != null) {
|
||||
if (file != null && settings.showBackgroundImage) {
|
||||
return Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: Container(
|
||||
|
@@ -1,15 +1,18 @@
|
||||
import 'dart:async';
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/websocket.dart';
|
||||
import 'package:island/screens/tray_manager.dart';
|
||||
import 'package:island/services/notify.dart';
|
||||
import 'package:island/services/sharing_intent.dart';
|
||||
import 'package:island/services/update_service.dart';
|
||||
import 'package:island/widgets/content/network_status_sheet.dart';
|
||||
import 'package:island/widgets/tour/tour.dart';
|
||||
import 'package:tray_manager/tray_manager.dart';
|
||||
|
||||
class AppWrapper extends HookConsumerWidget {
|
||||
class AppWrapper extends HookConsumerWidget with TrayListener {
|
||||
final Widget child;
|
||||
const AppWrapper({super.key, required this.child});
|
||||
|
||||
@@ -20,10 +23,16 @@ class AppWrapper extends HookConsumerWidget {
|
||||
Future(() {
|
||||
if (context.mounted) ntySubs = setupNotificationListener(context, ref);
|
||||
});
|
||||
|
||||
final sharingService = SharingIntentService();
|
||||
sharingService.initialize(context);
|
||||
|
||||
UpdateService().checkForUpdates(context);
|
||||
|
||||
TrayService.instance.initialize(this);
|
||||
|
||||
return () {
|
||||
TrayService.instance.dispose(this);
|
||||
sharingService.dispose();
|
||||
ntySubs?.cancel();
|
||||
};
|
||||
@@ -52,4 +61,27 @@ class AppWrapper extends HookConsumerWidget {
|
||||
|
||||
return TourTriggerWidget(key: UniqueKey(), child: child);
|
||||
}
|
||||
|
||||
void _trayIconPrimaryAction() {
|
||||
appWindow.show();
|
||||
}
|
||||
|
||||
void _trayIconSecondaryAction() {
|
||||
trayManager.popUpContextMenu();
|
||||
}
|
||||
|
||||
@override
|
||||
void onTrayIconMouseUp() {
|
||||
_trayIconPrimaryAction();
|
||||
}
|
||||
|
||||
@override
|
||||
void onTrayIconRightMouseDown() {
|
||||
_trayIconSecondaryAction();
|
||||
}
|
||||
|
||||
@override
|
||||
void onTrayMenuItemClick(MenuItem menuItem) {
|
||||
TrayService.instance.handleAction(menuItem);
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/services/file.dart';
|
||||
import 'package:island/utils/format.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
@@ -284,6 +285,13 @@ class AttachmentPreview extends HookConsumerWidget {
|
||||
Builder(
|
||||
key: ValueKey(item.hashCode),
|
||||
builder: (context) {
|
||||
final fallbackIcon = switch (item.type) {
|
||||
UniversalFileType.video => Symbols.video_file,
|
||||
UniversalFileType.audio => Symbols.audio_file,
|
||||
UniversalFileType.image => Symbols.image,
|
||||
_ => Symbols.insert_drive_file,
|
||||
};
|
||||
|
||||
if (item.isOnCloud) {
|
||||
return CloudFileWidget(item: item.data);
|
||||
} else if (item.data is XFile) {
|
||||
@@ -309,9 +317,23 @@ class AttachmentPreview extends HookConsumerWidget {
|
||||
: Image.file(File(file.path));
|
||||
default:
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Symbols.document_scanner),
|
||||
Icon(fallbackIcon),
|
||||
const Gap(6),
|
||||
Text(file.name),
|
||||
FutureBuilder(
|
||||
future: file.length(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final size = snapshot.data as int;
|
||||
return Text(
|
||||
formatFileSize(size),
|
||||
).fontSize(11);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -321,7 +343,14 @@ class AttachmentPreview extends HookConsumerWidget {
|
||||
return Image.memory(item.data);
|
||||
default:
|
||||
return Column(
|
||||
children: [const Icon(Symbols.document_scanner)],
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(fallbackIcon),
|
||||
const Gap(6),
|
||||
Text(
|
||||
formatFileSize(item.data.length),
|
||||
).fontSize(11),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/utils/format.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/sensitive.dart';
|
||||
@@ -359,16 +360,6 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
String formatFileSize(int bytes) {
|
||||
if (bytes <= 0) return '0 B';
|
||||
if (bytes < 1024) return '$bytes B';
|
||||
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB';
|
||||
if (bytes < 1024 * 1024 * 1024) {
|
||||
return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB';
|
||||
}
|
||||
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB';
|
||||
}
|
||||
|
||||
void showInfoSheet() {
|
||||
final theme = Theme.of(context);
|
||||
final exifData = item.fileMeta?['exif'] as Map<String, dynamic>? ?? {};
|
||||
|
@@ -1,15 +1,19 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/services/time.dart';
|
||||
import 'package:island/utils/format.dart';
|
||||
import 'package:island/widgets/content/audio.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
import 'image.dart';
|
||||
import 'video.dart';
|
||||
@@ -60,7 +64,45 @@ class CloudFileWidget extends HookConsumerWidget {
|
||||
child: UniversalAudio(uri: uri, filename: item.name),
|
||||
),
|
||||
),
|
||||
_ => Text('Unable render for ${item.mimeType}'),
|
||||
_ => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.insert_drive_file,
|
||||
size: 48,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
item.name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatFileSize(item.size),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const Gap(8),
|
||||
TextButton.icon(
|
||||
onPressed: () {
|
||||
launchUrlString(
|
||||
'https://fs.solian.app/files/${item.id}',
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
icon: const Icon(Symbols.launch),
|
||||
label: Text('openInBrowser').tr(),
|
||||
),
|
||||
],
|
||||
).padding(all: 8),
|
||||
};
|
||||
|
||||
if (heroTag != null) {
|
||||
|
@@ -52,12 +52,10 @@ class UniversalImage extends StatelessWidget {
|
||||
},
|
||||
errorWidget: (context, url, error) {
|
||||
return Image.asset(
|
||||
'assets/images/media-offline.png',
|
||||
'assets/images/media-offline.jpg',
|
||||
fit: BoxFit.cover,
|
||||
key: Key('image-broke-$uri'),
|
||||
);
|
||||
// return const Center(
|
||||
// child: Icon(Icons.broken_image, color: Colors.white, size: 16),
|
||||
// );
|
||||
},
|
||||
),
|
||||
],
|
||||
|
67
lib/widgets/extended_refresh_indicator.dart
Normal file
67
lib/widgets/extended_refresh_indicator.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class RefreshIntent extends Intent {
|
||||
const RefreshIntent();
|
||||
}
|
||||
|
||||
class ExtendedRefreshIndicator extends StatefulWidget {
|
||||
final Widget child;
|
||||
final RefreshCallback onRefresh;
|
||||
|
||||
const ExtendedRefreshIndicator({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.onRefresh,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ExtendedRefreshIndicator> createState() =>
|
||||
_ExtendedRefreshIndicatorState();
|
||||
}
|
||||
|
||||
class _ExtendedRefreshIndicatorState extends State<ExtendedRefreshIndicator> {
|
||||
late final FocusNode _focusNode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode = FocusNode();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_focusNode.requestFocus();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyR):
|
||||
const RefreshIntent(),
|
||||
LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.keyR):
|
||||
const RefreshIntent(),
|
||||
LogicalKeySet(LogicalKeyboardKey.f5): const RefreshIntent(),
|
||||
},
|
||||
child: Actions(
|
||||
actions: <Type, Action<Intent>>{
|
||||
RefreshIntent: CallbackAction<RefreshIntent>(
|
||||
onInvoke: (RefreshIntent intent) => widget.onRefresh(),
|
||||
),
|
||||
},
|
||||
child: Focus(
|
||||
focusNode: _focusNode,
|
||||
child: RefreshIndicator(
|
||||
onRefresh: widget.onRefresh,
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -388,26 +389,32 @@ class ComposeLogic {
|
||||
}
|
||||
|
||||
static Future<void> pickPhotoMedia(WidgetRef ref, ComposeState state) async {
|
||||
final result = await ref
|
||||
.watch(imagePickerProvider)
|
||||
.pickMultiImage(requestFullMetadata: true);
|
||||
if (result.isEmpty) return;
|
||||
final result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.image,
|
||||
allowMultiple: true,
|
||||
allowCompression: false,
|
||||
);
|
||||
if (result == null || result.count == 0) return;
|
||||
state.attachments.value = [
|
||||
...state.attachments.value,
|
||||
...result.map(
|
||||
(e) => UniversalFile(data: e, type: UniversalFileType.image),
|
||||
...result.files.map(
|
||||
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.image),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
static Future<void> pickVideoMedia(WidgetRef ref, ComposeState state) async {
|
||||
final result = await ref
|
||||
.watch(imagePickerProvider)
|
||||
.pickVideo(source: ImageSource.gallery);
|
||||
if (result == null) return;
|
||||
final result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.video,
|
||||
allowMultiple: true,
|
||||
allowCompression: false,
|
||||
);
|
||||
if (result == null || result.count == 0) return;
|
||||
state.attachments.value = [
|
||||
...state.attachments.value,
|
||||
UniversalFile(data: result, type: UniversalFileType.video),
|
||||
...result.files.map(
|
||||
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.video),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -105,7 +106,7 @@ class PostFeaturedList extends HookConsumerWidget {
|
||||
spacing: 8,
|
||||
children: [
|
||||
const Icon(Symbols.highlight),
|
||||
Text('Highlight Posts'),
|
||||
const Text('highlightPost').tr(),
|
||||
Spacer(),
|
||||
IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
|
@@ -36,6 +36,7 @@ class PostActionableItem extends HookConsumerWidget {
|
||||
final bool isShowReference;
|
||||
final bool isEmbedReply;
|
||||
final bool isEmbedOpenable;
|
||||
final bool isCompact;
|
||||
final double? borderRadius;
|
||||
final VoidCallback? onRefresh;
|
||||
final Function(SnPost)? onUpdate;
|
||||
@@ -48,6 +49,7 @@ class PostActionableItem extends HookConsumerWidget {
|
||||
this.isShowReference = true,
|
||||
this.isEmbedReply = true,
|
||||
this.isEmbedOpenable = false,
|
||||
this.isCompact = false,
|
||||
this.borderRadius,
|
||||
this.onRefresh,
|
||||
this.onUpdate,
|
||||
@@ -76,6 +78,7 @@ class PostActionableItem extends HookConsumerWidget {
|
||||
isEmbedReply: isEmbedReply,
|
||||
isEmbedOpenable: isEmbedOpenable,
|
||||
isTextSelectable: false,
|
||||
isCompact: isCompact,
|
||||
onRefresh: onRefresh,
|
||||
onUpdate: onUpdate,
|
||||
onOpen: onOpen,
|
||||
@@ -298,6 +301,7 @@ class PostItem extends HookConsumerWidget {
|
||||
final bool isEmbedOpenable;
|
||||
final bool isTextSelectable;
|
||||
final bool isTranslatable;
|
||||
final bool isCompact;
|
||||
final VoidCallback? onRefresh;
|
||||
final Function(SnPost)? onUpdate;
|
||||
final VoidCallback? onOpen;
|
||||
@@ -311,6 +315,7 @@ class PostItem extends HookConsumerWidget {
|
||||
this.isEmbedOpenable = false,
|
||||
this.isTextSelectable = true,
|
||||
this.isTranslatable = true,
|
||||
this.isCompact = false,
|
||||
this.onRefresh,
|
||||
this.onUpdate,
|
||||
this.onOpen,
|
||||
@@ -340,7 +345,14 @@ class PostItem extends HookConsumerWidget {
|
||||
final delta = isRemoving ? -1 : 1;
|
||||
final reactionsCount = Map<String, int>.from(item.reactionsCount);
|
||||
reactionsCount[symbol] = (reactionsCount[symbol] ?? 0) + delta;
|
||||
onUpdate?.call(item.copyWith(reactionsCount: reactionsCount));
|
||||
final reactionsMade = Map<String, bool>.from(item.reactionsMade);
|
||||
reactionsMade[symbol] = delta == 1 ? true : false;
|
||||
onUpdate?.call(
|
||||
item.copyWith(
|
||||
reactionsCount: reactionsCount,
|
||||
reactionsMade: reactionsMade,
|
||||
),
|
||||
);
|
||||
HapticFeedback.heavyImpact();
|
||||
});
|
||||
reacting.value = false;
|
||||
@@ -458,54 +470,64 @@ class PostItem extends HookConsumerWidget {
|
||||
PostHeader(
|
||||
item: item,
|
||||
isFullPost: isFullPost,
|
||||
isCompact: isCompact,
|
||||
renderingPadding: renderingPadding,
|
||||
trailing: IconButton(
|
||||
icon:
|
||||
mostReaction == null
|
||||
? const Icon(Symbols.add_reaction)
|
||||
: Badge(
|
||||
label: Center(
|
||||
child: Text(
|
||||
'x${item.reactionsCount[mostReaction]}',
|
||||
style: const TextStyle(fontSize: 11),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
offset: const Offset(4, 20),
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary.withOpacity(0.75),
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
child: Text(
|
||||
kReactionTemplates[mostReaction]?.icon ?? '',
|
||||
style: const TextStyle(fontSize: 20),
|
||||
trailing:
|
||||
isCompact
|
||||
? null
|
||||
: IconButton(
|
||||
icon:
|
||||
mostReaction == null
|
||||
? const Icon(Symbols.add_reaction)
|
||||
: Badge(
|
||||
label: Center(
|
||||
child: Text(
|
||||
'x${item.reactionsCount[mostReaction]}',
|
||||
style: const TextStyle(fontSize: 11),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
offset: const Offset(4, 20),
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary.withOpacity(0.75),
|
||||
textColor:
|
||||
Theme.of(context).colorScheme.onPrimary,
|
||||
child: Text(
|
||||
kReactionTemplates[mostReaction]?.icon ?? '',
|
||||
style: const TextStyle(fontSize: 20),
|
||||
),
|
||||
),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
(item.reactionsMade[mostReaction] ?? false)
|
||||
? Theme.of(
|
||||
context,
|
||||
).colorScheme.primary.withOpacity(0.5)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
(item.reactionsMade[mostReaction] ?? false)
|
||||
? Theme.of(context).colorScheme.primary.withOpacity(0.5)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
builder: (BuildContext context) {
|
||||
return _PostReactionSheet(
|
||||
reactionsCount: item.reactionsCount,
|
||||
reactionsMade: item.reactionsMade,
|
||||
onReact: (symbol, attitude) {
|
||||
reactPost(symbol, attitude);
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
builder: (BuildContext context) {
|
||||
return _PostReactionSheet(
|
||||
reactionsCount: item.reactionsCount,
|
||||
reactionsMade: item.reactionsMade,
|
||||
onReact: (symbol, attitude) {
|
||||
reactPost(symbol, attitude);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
padding: EdgeInsets.zero,
|
||||
visualDensity: const VisualDensity(horizontal: -3, vertical: -3),
|
||||
),
|
||||
padding: EdgeInsets.zero,
|
||||
visualDensity: const VisualDensity(
|
||||
horizontal: -3,
|
||||
vertical: -3,
|
||||
),
|
||||
),
|
||||
),
|
||||
PostBody(
|
||||
item: item,
|
||||
|
@@ -10,6 +10,7 @@ import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/post/post_item.dart';
|
||||
import 'package:island/widgets/post/post_shared.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:super_context_menu/super_context_menu.dart';
|
||||
|
||||
class PostItemCreator extends HookConsumerWidget {
|
||||
@@ -33,7 +34,7 @@ class PostItemCreator extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final renderingPadding =
|
||||
padding ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 16);
|
||||
padding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8);
|
||||
|
||||
return ContextMenuWidget(
|
||||
menuProvider: (_) {
|
||||
@@ -97,18 +98,22 @@ class PostItemCreator extends HookConsumerWidget {
|
||||
context.goNamed('postDetail', pathParameters: {'id': item.id});
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: renderingPadding,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
PostHeader(item: item),
|
||||
PostBody(item: item),
|
||||
ReferencedPostWidget(item: item),
|
||||
const Gap(16),
|
||||
_buildAnalyticsSection(context),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Gap(renderingPadding.vertical),
|
||||
PostHeader(item: item, renderingPadding: renderingPadding),
|
||||
PostBody(item: item, renderingPadding: renderingPadding),
|
||||
ReferencedPostWidget(
|
||||
item: item,
|
||||
renderingPadding: renderingPadding,
|
||||
),
|
||||
const Gap(16),
|
||||
_buildAnalyticsSection(
|
||||
context,
|
||||
).padding(horizontal: renderingPadding.horizontal),
|
||||
Gap(renderingPadding.vertical),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@@ -532,6 +532,7 @@ class PostHeader extends StatelessWidget {
|
||||
final bool isInteractive;
|
||||
final EdgeInsets renderingPadding;
|
||||
final bool isRelativeTime;
|
||||
final bool isCompact;
|
||||
|
||||
const PostHeader({
|
||||
super.key,
|
||||
@@ -541,6 +542,7 @@ class PostHeader extends StatelessWidget {
|
||||
this.isInteractive = true,
|
||||
this.renderingPadding = EdgeInsets.zero,
|
||||
this.isRelativeTime = true,
|
||||
this.isCompact = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -584,11 +586,27 @@ class PostHeader extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text(item.publisher.nick).bold(),
|
||||
Flexible(
|
||||
child:
|
||||
Text(
|
||||
item.publisher.nick,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).bold(),
|
||||
),
|
||||
if (item.publisher.verification != null)
|
||||
VerificationMark(mark: item.publisher.verification!),
|
||||
if (item.realm == null)
|
||||
Text('@${item.publisher.name}').fontSize(11)
|
||||
Flexible(
|
||||
child:
|
||||
isCompact
|
||||
? const SizedBox.shrink()
|
||||
: Text(
|
||||
'@${item.publisher.name}',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).fontSize(11),
|
||||
)
|
||||
else
|
||||
...([
|
||||
const Icon(Symbols.arrow_right, size: 14),
|
||||
@@ -762,7 +780,9 @@ class PostBody extends ConsumerWidget {
|
||||
).padding(bottom: 4),
|
||||
MarkdownTextContent(
|
||||
content:
|
||||
item.isTruncated ? '${item.content!}...' : item.content!,
|
||||
item.isTruncated
|
||||
? '${item.content!}...'
|
||||
: item.content ?? '',
|
||||
isSelectable: isTextSelectable,
|
||||
),
|
||||
if (translationSection != null) translationSection!,
|
||||
|
@@ -25,7 +25,7 @@ class PostShuffleScreen extends HookConsumerWidget {
|
||||
return cardSwiperController.dispose;
|
||||
}, []);
|
||||
|
||||
const kBottomControlHeight = 64.0;
|
||||
const kBottomControlHeight = 80.0;
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: const Text('postShuffle').tr()),
|
||||
@@ -41,6 +41,7 @@ class PostShuffleScreen extends HookConsumerWidget {
|
||||
? CardSwiper(
|
||||
controller: cardSwiperController,
|
||||
cardsCount: postListState.value!.items.length,
|
||||
isLoop: false,
|
||||
cardBuilder: (
|
||||
context,
|
||||
index,
|
||||
|
@@ -12,6 +12,7 @@ import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:flutter_popup_card/flutter_popup_card.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
|
||||
part 'picker.g.dart';
|
||||
|
||||
@@ -208,7 +209,7 @@ class _PackSwitcherState extends State<_PackSwitcher> {
|
||||
|
||||
// Content
|
||||
Expanded(
|
||||
child: RefreshIndicator(
|
||||
child: ExtendedRefreshIndicator(
|
||||
onRefresh: widget.onRefresh,
|
||||
child: _StickersGrid(
|
||||
pack: selectedPack,
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <record_linux/record_linux_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <super_native_extensions/super_native_extensions_plugin.h>
|
||||
#include <tray_manager/tray_manager_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
#include <volume_controller/volume_controller_plugin.h>
|
||||
|
||||
@@ -74,6 +75,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) super_native_extensions_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "SuperNativeExtensionsPlugin");
|
||||
super_native_extensions_plugin_register_with_registrar(super_native_extensions_registrar);
|
||||
g_autoptr(FlPluginRegistrar) tray_manager_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin");
|
||||
tray_manager_plugin_register_with_registrar(tray_manager_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
|
@@ -19,6 +19,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
record_linux
|
||||
sqlite3_flutter_libs
|
||||
super_native_extensions
|
||||
tray_manager
|
||||
url_launcher_linux
|
||||
volume_controller
|
||||
)
|
||||
|
@@ -16,6 +16,7 @@ import firebase_core
|
||||
import firebase_crashlytics
|
||||
import firebase_messaging
|
||||
import flutter_inappwebview_macos
|
||||
import flutter_local_notifications
|
||||
import flutter_platform_alert
|
||||
import flutter_secure_storage_macos
|
||||
import flutter_timezone
|
||||
@@ -37,6 +38,7 @@ import sign_in_with_apple
|
||||
import sqflite_darwin
|
||||
import sqlite3_flutter_libs
|
||||
import super_native_extensions
|
||||
import tray_manager
|
||||
import url_launcher_macos
|
||||
import volume_controller
|
||||
import wakelock_plus
|
||||
@@ -53,6 +55,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin"))
|
||||
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
FlutterPlatformAlertPlugin.register(with: registry.registrar(forPlugin: "FlutterPlatformAlertPlugin"))
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin"))
|
||||
@@ -74,6 +77,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
||||
SuperNativeExtensionsPlugin.register(with: registry.registrar(forPlugin: "SuperNativeExtensionsPlugin"))
|
||||
TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
VolumeControllerPlugin.register(with: registry.registrar(forPlugin: "VolumeControllerPlugin"))
|
||||
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
||||
|
@@ -13,85 +13,85 @@ PODS:
|
||||
- FlutterMacOS
|
||||
- file_selector_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- Firebase/CoreOnly (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- Firebase/Crashlytics (12.0.0):
|
||||
- Firebase/CoreOnly (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- Firebase/Crashlytics (12.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseCrashlytics (~> 12.0.0)
|
||||
- Firebase/Messaging (12.0.0):
|
||||
- FirebaseCrashlytics (~> 12.2.0)
|
||||
- Firebase/Messaging (12.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 12.0.0)
|
||||
- firebase_analytics (12.0.0):
|
||||
- FirebaseMessaging (~> 12.2.0)
|
||||
- firebase_analytics (12.0.1):
|
||||
- firebase_core
|
||||
- FirebaseAnalytics (= 12.0.0)
|
||||
- FirebaseAnalytics (= 12.2.0)
|
||||
- FlutterMacOS
|
||||
- firebase_core (4.0.0):
|
||||
- Firebase/CoreOnly (~> 12.0.0)
|
||||
- firebase_core (4.1.0):
|
||||
- Firebase/CoreOnly (~> 12.2.0)
|
||||
- FlutterMacOS
|
||||
- firebase_crashlytics (5.0.0):
|
||||
- Firebase/CoreOnly (~> 12.0.0)
|
||||
- Firebase/Crashlytics (~> 12.0.0)
|
||||
- firebase_crashlytics (5.0.1):
|
||||
- Firebase/CoreOnly (~> 12.2.0)
|
||||
- Firebase/Crashlytics (~> 12.2.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_messaging (16.0.0):
|
||||
- Firebase/CoreOnly (~> 12.0.0)
|
||||
- Firebase/Messaging (~> 12.0.0)
|
||||
- firebase_messaging (16.0.1):
|
||||
- Firebase/CoreOnly (~> 12.2.0)
|
||||
- Firebase/Messaging (~> 12.2.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- FirebaseAnalytics (12.0.0):
|
||||
- FirebaseAnalytics/Default (= 12.0.0)
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseAnalytics (12.2.0):
|
||||
- FirebaseAnalytics/Default (= 12.2.0)
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseAnalytics/Default (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- GoogleAppMeasurement/Default (= 12.0.0)
|
||||
- FirebaseAnalytics/Default (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleAppMeasurement/Default (= 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseCore (12.0.0):
|
||||
- FirebaseCoreInternal (~> 12.0.0)
|
||||
- FirebaseCore (12.2.0):
|
||||
- FirebaseCoreInternal (~> 12.2.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Logger (~> 8.1)
|
||||
- FirebaseCoreExtension (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseCoreInternal (12.0.0):
|
||||
- FirebaseCoreExtension (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseCoreInternal (12.2.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- FirebaseCrashlytics (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseRemoteConfigInterop (~> 12.0.0)
|
||||
- FirebaseSessions (~> 12.0.0)
|
||||
- FirebaseCrashlytics (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- FirebaseRemoteConfigInterop (~> 12.2.0)
|
||||
- FirebaseSessions (~> 12.2.0)
|
||||
- GoogleDataTransport (~> 10.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseInstallations (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseMessaging (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseMessaging (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleDataTransport (~> 10.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Reachability (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseRemoteConfigInterop (12.0.0)
|
||||
- FirebaseSessions (12.0.0):
|
||||
- FirebaseCore (~> 12.0.0)
|
||||
- FirebaseCoreExtension (~> 12.0.0)
|
||||
- FirebaseInstallations (~> 12.0.0)
|
||||
- FirebaseRemoteConfigInterop (12.2.0)
|
||||
- FirebaseSessions (12.2.0):
|
||||
- FirebaseCore (~> 12.2.0)
|
||||
- FirebaseCoreExtension (~> 12.2.0)
|
||||
- FirebaseInstallations (~> 12.2.0)
|
||||
- GoogleDataTransport (~> 10.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
@@ -100,6 +100,8 @@ PODS:
|
||||
- flutter_inappwebview_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- OrderedSet (~> 6.0.3)
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- FlutterMacOS
|
||||
- flutter_platform_alert (0.0.1):
|
||||
- FlutterMacOS
|
||||
- flutter_secure_storage_macos (6.1.3):
|
||||
@@ -109,30 +111,30 @@ PODS:
|
||||
- flutter_udid (0.0.1):
|
||||
- FlutterMacOS
|
||||
- SAMKeychain
|
||||
- flutter_webrtc (1.0.0):
|
||||
- flutter_webrtc (1.1.0):
|
||||
- FlutterMacOS
|
||||
- WebRTC-SDK (= 137.7151.02)
|
||||
- WebRTC-SDK (= 137.7151.03)
|
||||
- FlutterMacOS (1.0.0)
|
||||
- gal (1.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- GoogleAppMeasurement/Core (12.0.0):
|
||||
- GoogleAppMeasurement/Core (12.2.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/Default (12.0.0):
|
||||
- GoogleAdsOnDeviceConversion (= 2.1.0)
|
||||
- GoogleAppMeasurement/Core (= 12.0.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (= 12.0.0)
|
||||
- GoogleAppMeasurement/Default (12.2.0):
|
||||
- GoogleAdsOnDeviceConversion (= 2.3.0)
|
||||
- GoogleAppMeasurement/Core (= 12.2.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (= 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (12.0.0):
|
||||
- GoogleAppMeasurement/Core (= 12.0.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (12.2.0):
|
||||
- GoogleAppMeasurement/Core (= 12.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
@@ -173,7 +175,7 @@ PODS:
|
||||
- livekit_client (2.5.0):
|
||||
- flutter_webrtc
|
||||
- FlutterMacOS
|
||||
- WebRTC-SDK (= 137.7151.02)
|
||||
- WebRTC-SDK (= 137.7151.03)
|
||||
- local_auth_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
@@ -237,13 +239,15 @@ PODS:
|
||||
- sqlite3/session
|
||||
- super_native_extensions (0.0.1):
|
||||
- FlutterMacOS
|
||||
- tray_manager (0.0.1):
|
||||
- FlutterMacOS
|
||||
- url_launcher_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- volume_controller (0.0.1):
|
||||
- FlutterMacOS
|
||||
- wakelock_plus (0.0.1):
|
||||
- FlutterMacOS
|
||||
- WebRTC-SDK (137.7151.02)
|
||||
- WebRTC-SDK (137.7151.03)
|
||||
|
||||
DEPENDENCIES:
|
||||
- bitsdojo_window_macos (from `Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos`)
|
||||
@@ -258,6 +262,7 @@ DEPENDENCIES:
|
||||
- firebase_crashlytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_crashlytics/macos`)
|
||||
- firebase_messaging (from `Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos`)
|
||||
- flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`)
|
||||
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
|
||||
- flutter_platform_alert (from `Flutter/ephemeral/.symlinks/plugins/flutter_platform_alert/macos`)
|
||||
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
|
||||
- flutter_timezone (from `Flutter/ephemeral/.symlinks/plugins/flutter_timezone/macos`)
|
||||
@@ -280,6 +285,7 @@ DEPENDENCIES:
|
||||
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
||||
- super_native_extensions (from `Flutter/ephemeral/.symlinks/plugins/super_native_extensions/macos`)
|
||||
- tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
- volume_controller (from `Flutter/ephemeral/.symlinks/plugins/volume_controller/macos`)
|
||||
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
|
||||
@@ -332,6 +338,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos
|
||||
flutter_inappwebview_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos
|
||||
flutter_local_notifications:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos
|
||||
flutter_platform_alert:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_platform_alert/macos
|
||||
flutter_secure_storage_macos:
|
||||
@@ -376,6 +384,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin
|
||||
super_native_extensions:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/super_native_extensions/macos
|
||||
tray_manager:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos
|
||||
url_launcher_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||
volume_controller:
|
||||
@@ -391,33 +401,34 @@ SPEC CHECKSUMS:
|
||||
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
|
||||
file_saver: e35bd97de451dde55ff8c38862ed7ad0f3418d0f
|
||||
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
|
||||
Firebase: 800d487043c0557d9faed71477a38d9aafb08a41
|
||||
firebase_analytics: 53f0dc87ad10f56a6df8746da60d8a5fe41f886f
|
||||
firebase_core: eeea10f64026b68cd0bc3dee079ab4717e22909e
|
||||
firebase_crashlytics: 7be1dacc38809971354def57193b280636a3d51a
|
||||
firebase_messaging: 5eefcd5bde556bfacdd9968e11c52f39032dfbe5
|
||||
FirebaseAnalytics: 6d790cd1b159b4eb61a99948df0934ce505a34f7
|
||||
FirebaseCore: 055f4ab117d5964158c833f3d5e7ec6d91648d4a
|
||||
FirebaseCoreExtension: 639afb3de6abd611952be78a794c54a47fa0f361
|
||||
FirebaseCoreInternal: dedc28e569a4be85f38f3d6af1070a2e12018d55
|
||||
FirebaseCrashlytics: db75aa0cab8d00f68406fa247c32fe17ade884d7
|
||||
FirebaseInstallations: d4c7c958f99c8860d7fcece786314ae790e2f988
|
||||
FirebaseMessaging: af49f8d7c0a3d2a017d9302c80946f45a7777dde
|
||||
FirebaseRemoteConfigInterop: bfa0ea72ba3dc5af739777296424e46bd6f42613
|
||||
FirebaseSessions: 4e784acda213108aafef536535cdfc03504acc42
|
||||
Firebase: 26f6f8d460603af3df970ad505b16b15f5e2e9a1
|
||||
firebase_analytics: efe6e51156f4565f3791d99072e8e3b0fcca0e91
|
||||
firebase_core: a8d3b82b0a87bd1d0ebc21e686b37e939c56e6e1
|
||||
firebase_crashlytics: fdbe67a1229a9e583ebf2b155541491aa83927bb
|
||||
firebase_messaging: 6fb526705903e2e56e38a6ff56b43668b052b01b
|
||||
FirebaseAnalytics: e04e23bc070e3014aa5cf4980f9df7ce5cd79ec8
|
||||
FirebaseCore: 311c48a147ad4a0ab7febbaed89e8025c67510cd
|
||||
FirebaseCoreExtension: 73af080c22a2f7b44cefa391dc08f7e4ee162cb5
|
||||
FirebaseCoreInternal: 56ea29f3dad2894f81b060f706f9d53509b6ed3b
|
||||
FirebaseCrashlytics: f83cbf176d5c637ade108c0aacf1ccbd5ec499bf
|
||||
FirebaseInstallations: 3e884b01feabdf67582a80f3250425a00979b4ed
|
||||
FirebaseMessaging: 43ec73bbfedd0c385a849bb91593ab4ad4b9e48e
|
||||
FirebaseRemoteConfigInterop: 0896fd52ab72586a355c8f389ff85aaa9e5375e1
|
||||
FirebaseSessions: f4692789e770bec66ce17d772c0e9561c4f11737
|
||||
flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d
|
||||
flutter_local_notifications: 4bf37a31afde695b56091b4ae3e4d9c7a7e6cda0
|
||||
flutter_platform_alert: 8fa7a7c21f95b26d08b4a3891936ca27e375f284
|
||||
flutter_secure_storage_macos: 7f45e30f838cf2659862a4e4e3ee1c347c2b3b54
|
||||
flutter_timezone: d59eea86178cbd7943cd2431cc2eaa9850f935d8
|
||||
flutter_udid: d26e455e8c06174e6aff476e147defc6cae38495
|
||||
flutter_webrtc: 0d70bd8782c19bde286dc52f766eebbea26de201
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
flutter_webrtc: 1ce7fe9a42f085286378355a575e682edd7f114d
|
||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||
GoogleAppMeasurement: 8f6ab04ad6ae493b53fcf56bd26323fb2f1384f3
|
||||
GoogleAppMeasurement: 09f341dfa8527d1612a09cbfe809a242c0b737af
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba
|
||||
livekit_client: 0b0515e03858b86a7c14cc7fd6f772331f6ee84c
|
||||
livekit_client: 5a5c0f1081978542bbf9a986c7ac9bffcdb73906
|
||||
local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19
|
||||
media_kit_libs_macos_video: 85a23e549b5f480e72cae3e5634b5514bc692f65
|
||||
media_kit_video: fa6564e3799a0a28bff39442334817088b7ca758
|
||||
@@ -437,10 +448,11 @@ SPEC CHECKSUMS:
|
||||
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
|
||||
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
|
||||
super_native_extensions: c2795d6d9aedf4a79fae25cb6160b71b50549189
|
||||
tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166
|
||||
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
|
||||
volume_controller: 5c068e6d085c80dadd33fc2c918d2114b775b3dd
|
||||
wakelock_plus: 21ddc249ac4b8d018838dbdabd65c5976c308497
|
||||
WebRTC-SDK: d20de357dcbf7c9696b124b39f3ff62125107e4b
|
||||
WebRTC-SDK: 69d4e56b0b4b27d788e87bab9b9a1326ed05b1e3
|
||||
|
||||
PODFILE CHECKSUM: 346bfb2deb41d4a6ebd6f6799f92188bde2d246f
|
||||
|
||||
|
@@ -586,7 +586,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
@@ -674,7 +674,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -724,7 +724,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
@@ -32,5 +32,14 @@
|
||||
<string>public.app-category.social-networking</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSSupportsAutomaticTermination</key>
|
||||
<false/>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<true/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
218
pubspec.lock
218
pubspec.lock
@@ -13,10 +13,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
sha256: bb84ee51e527053dd8e25ecc9f97a6abfdc19130fb4d883e4e8585e23e7e6dd8
|
||||
sha256: "948f7d74f41dd6f2d563ea9f4c21d7ea764f8e047d2b24138974c19c24d37eb6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.60"
|
||||
version: "1.3.61"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -189,10 +189,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: ba95c961bafcd8686d1cf63be864eb59447e795e124d98d6a27d91fcd13602fb
|
||||
sha256: a30f0a0e38671e89a492c44d005b5545b830a961575bbd8336d42869ff71066d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.11.1"
|
||||
version: "8.12.0"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -613,34 +613,34 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_analytics
|
||||
sha256: "07146e89e11302c6b07e3465c2c556ebcdd0053a3c5b1aa9bfd3203b778e5b4c"
|
||||
sha256: dde9d6a7b69b07551a77cfb913c81c64804f7602b07541328322c321e73f2a0e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.0.0"
|
||||
version: "12.0.1"
|
||||
firebase_analytics_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_analytics_platform_interface
|
||||
sha256: "27e81a0efc821bec6cba64abc1083b91c8ddbad28eeb4c6f6b7c78a59d06f259"
|
||||
sha256: "4008d82a58edcbedec34a7b39f457eed24181cb9c89782c104828c42e4c859b2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "5.0.1"
|
||||
firebase_analytics_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_analytics_web
|
||||
sha256: "7d87f47462042a7d9125e3123db2783bc72917d85e2719d4cb6aeaec209605e1"
|
||||
sha256: db2a2e8803f5471a5f89b4abacae95ae27e0644f77526879fb81a2c1abc12b5f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
version: "0.6.0+1"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
sha256: "6b343e6f7b72a4f32d7ce8df8c9a28d8f54b4ac20d7c6500f3e8b3969afca457"
|
||||
sha256: "967dae9a65f69377beb9f4ab292ea63ce5befa1ce24682cab1b69ca4b7a46927"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.1.0"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -653,50 +653,50 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: "5d28b14dd32282fb7ce2b22b897362453755b6b8541d491127dc72b755bb7b16"
|
||||
sha256: f7ee08febc1c4451588ce58ffcf28edaee857e9a196fee88b85deb889990094a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.1.0"
|
||||
firebase_crashlytics:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_crashlytics
|
||||
sha256: "95b6871850b1a7e3b09c284c59a0c71fafcad3eee8ac1b6f06aaf8979290cbb8"
|
||||
sha256: f2e175a967712ee1f616ab8843390891a315428ba497ce3d256d4c46f32db6f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "5.0.1"
|
||||
firebase_crashlytics_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_crashlytics_platform_interface
|
||||
sha256: ba5b7a916f1ebedc6db35b33abdc618f202fc25e0792088dfba698e19fec9c09
|
||||
sha256: b49b90af4a1fd8f30b58abd90af88371969bea51b62838a4f4e737c2098b725e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.8.11"
|
||||
version: "3.8.12"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
sha256: "10272b553a49c13a6cedfd00121047157521f82a5d3f2a1706b9dd28342cc482"
|
||||
sha256: aad5dcdea5698499b70d74d5a53b1f6a9972f85f97225e4b7ac006dd8d4f9bac
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "16.0.0"
|
||||
version: "16.0.1"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
sha256: b846a305feb3f74ee3f0aace447f65a4696bc6550bc828ecf5a84a1b77473d16
|
||||
sha256: "825bc11767bf50a43dccf49b3026f847ec31d0f176139bfc48d662cc128b5014"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "4.7.1"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
sha256: "28714749880f7242c5fb3b1ee6c66b41f61453f02ae348b43c82957df80b87ae"
|
||||
sha256: db8dbdd79921245c4de02407e33cae2d1868683be18a5ba948d2af5311e3ef5d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.0.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -709,10 +709,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fl_chart
|
||||
sha256: "577aeac8ca414c25333334d7c4bb246775234c0e44b38b10a82b559dd4d764e7"
|
||||
sha256: d3f82f4a38e33ba23d05a08ff304d7d8b22d2a59a5503f20bd802966e915db89
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -886,14 +886,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
flutter_langdetect:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_langdetect
|
||||
sha256: "93bd865c7d5723eac614744abb32234ee4f593505a293bc17ef097bd55fbdf38"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -910,6 +902,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_local_notifications:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: a9966c850de5e445331b854fa42df96a8020066d67f125a5964cbc6556643f68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "19.4.1"
|
||||
flutter_local_notifications_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_linux
|
||||
sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_local_notifications_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_platform_interface
|
||||
sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.0"
|
||||
flutter_local_notifications_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_windows
|
||||
sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
flutter_localizations:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -967,10 +991,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "6382ce712ff69b0f719640ce957559dde459e55ecd433c767e06d139ddf16cab"
|
||||
sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.29"
|
||||
version: "2.0.30"
|
||||
flutter_popup_card:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1039,10 +1063,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845
|
||||
sha256: b9c2ad5872518a27507ab432d1fb97e8813b05f0fc693f9d40fad06d073e0678
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@@ -1081,18 +1105,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_webrtc
|
||||
sha256: "69095ba39b83da3de48286dfc0769aa8e9f10491f70058dc8d8ecc960ef7a260"
|
||||
sha256: "945d0a38b90fbca8257eadb167d8fb9fa7075d9a1939fd2953c10054454d1de2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
font_awesome_flutter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: font_awesome_flutter
|
||||
sha256: b738e35f8bb4957896c34957baf922f99c5d415b38ddc8b070d14b7fa95715d4
|
||||
sha256: "27af5982e6c510dec1ba038eff634fa284676ee84e3fd807225c80c4ad869177"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.9.1"
|
||||
version: "10.10.0"
|
||||
freezed:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -1153,18 +1177,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: go_router
|
||||
sha256: ced3fdc143c1437234ac3b8e985f3286cf138968bb83ca9a6f94d22f2951c6b9
|
||||
sha256: eb059dfe59f08546e9787f895bd01652076f996bcbf485a8609ef990419ad227
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "16.2.0"
|
||||
version: "16.2.1"
|
||||
google_fonts:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_fonts
|
||||
sha256: df9763500dadba0155373e9cb44e202ce21bd9ed5de6bdbd05c5854e86839cb8
|
||||
sha256: ebc94ed30fd13cefd397cb1658b593f21571f014b7d1197eeb41fb95f05d899a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
version: "6.3.1"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1257,10 +1281,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c
|
||||
sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.13"
|
||||
version: "0.8.13+1"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1369,26 +1393,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.9"
|
||||
version: "11.0.1"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.9"
|
||||
version: "3.0.10"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.0.2"
|
||||
lint:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1409,10 +1433,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: livekit_client
|
||||
sha256: b3db2d8afa8d1dbe4fd8dfc965fc9d661cb51a8d864ad199919575ce919a40fb
|
||||
sha256: "011affc0fca22b2f9b0e8827219dad9948f84f2bf057980693de13039de904c7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0+hotfix.1"
|
||||
version: "2.5.0+hotfix.3"
|
||||
local_auth:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1425,10 +1449,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: local_auth_android
|
||||
sha256: "316503f6772dea9c0c038bb7aac4f68ab00112d707d258c770f7fc3c250a2d88"
|
||||
sha256: "48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.51"
|
||||
version: "1.0.52"
|
||||
local_auth_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1457,10 +1481,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logger
|
||||
sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f"
|
||||
sha256: "55d6c23a6c15db14920e037fe7e0dc32e7cdaf3b64b4b25df2d541b5b6b81c0c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "2.6.1"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1513,10 +1537,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: material_symbols_icons
|
||||
sha256: b1342194e859b2774f920b484c46f54a37a845488e23d570385fbe3ede92ee9f
|
||||
sha256: "2cfd19bf1c3016b0de7298eb3d3444fcb6ef093d934deb870ceb946af89cfa58"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2867.0"
|
||||
version: "4.2872.0"
|
||||
media_kit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1581,6 +1605,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
menu_base:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: menu_base
|
||||
sha256: "820368014a171bd1241030278e6c2617354f492f5c703d7b7d4570a6b8b84405"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1721,10 +1753,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||
sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.17"
|
||||
version: "2.2.18"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1761,10 +1793,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
|
||||
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "7.0.1"
|
||||
photo_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2113,10 +2145,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "5bcf0772a761b04f8c6bf814721713de6f3e5d9d89caf8d3fe031b02a342379e"
|
||||
sha256: a2608114b1ffdcbc9c120eb71a0e207c71da56202852d4aab8a5e30a82269e74
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.11"
|
||||
version: "2.4.12"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2173,6 +2205,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
shortid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shortid
|
||||
sha256: d0b40e3dbb50497dad107e19c54ca7de0d1a274eb9b4404991e443dadb9ebedb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
sign_in_with_apple:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2254,10 +2294,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_android
|
||||
sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
|
||||
sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2+2"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2302,10 +2342,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlparser
|
||||
sha256: "7c859c803cf7e9a84d6db918bac824545045692bbe94a6386bd3a45132235d09"
|
||||
sha256: "57090342af1ce32bb499aa641f4ecdd2d6231b9403cea537ac059e803cc20d67"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.41.1"
|
||||
version: "0.41.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2406,10 +2446,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
version: "0.7.6"
|
||||
textfield_tags:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2443,6 +2483,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.0"
|
||||
tray_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: tray_manager
|
||||
sha256: "537e539f48cd82d8ee2240d4330158c7b44c7e043e8e18b5811f2f8f6b7df25a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
tuple:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2504,10 +2552,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "0aedad096a85b49df2e4725fa32118f9fa580f3b14af7a2d2221896a02cd5656"
|
||||
sha256: "69ee86740f2847b9a4ba6cffa74ed12ce500bbe2b07f3dc1e643439da60637b7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.17"
|
||||
version: "6.3.18"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2584,18 +2632,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: ca81fdfaf62a5ab45d7296614aea108d2c7d0efca8393e96174bf4d51e6725b0
|
||||
sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.18"
|
||||
version: "1.1.19"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.2.0"
|
||||
very_good_infinite_list:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2616,10 +2664,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.0.0"
|
||||
version: "15.0.2"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2720,10 +2768,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
version: "6.6.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2733,5 +2781,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.8.0 <4.0.0"
|
||||
dart: ">=3.9.0 <4.0.0"
|
||||
flutter: ">=3.32.0"
|
||||
|
28
pubspec.yaml
28
pubspec.yaml
@@ -39,7 +39,7 @@ dependencies:
|
||||
flutter_hooks: ^0.21.3+1
|
||||
hooks_riverpod: ^2.6.1
|
||||
bitsdojo_window: ^0.1.6
|
||||
go_router: ^16.2.0
|
||||
go_router: ^16.2.1
|
||||
styled_widget: ^0.4.1
|
||||
shared_preferences: ^2.5.3
|
||||
flutter_riverpod: ^2.6.1
|
||||
@@ -53,7 +53,7 @@ dependencies:
|
||||
flutter_highlight: ^0.7.0
|
||||
uuid: ^4.5.1
|
||||
url_launcher: ^6.3.2
|
||||
google_fonts: ^6.3.0
|
||||
google_fonts: ^6.3.1
|
||||
gap: ^3.0.1
|
||||
cached_network_image: ^3.4.1
|
||||
web: ^1.1.1
|
||||
@@ -76,14 +76,14 @@ dependencies:
|
||||
file_picker: ^10.3.2
|
||||
riverpod_annotation: ^2.6.1
|
||||
image_picker_platform_interface: ^2.11.0
|
||||
image_picker_android: ^0.8.13
|
||||
image_picker_android: ^0.8.13+1
|
||||
super_context_menu: ^0.9.1
|
||||
modal_bottom_sheet: ^3.0.0
|
||||
firebase_messaging: ^16.0.0
|
||||
firebase_messaging: ^16.0.1
|
||||
flutter_udid: ^4.0.0
|
||||
firebase_core: ^4.0.0
|
||||
firebase_core: ^4.1.0
|
||||
web_socket_channel: ^3.0.3
|
||||
material_symbols_icons: ^4.2867.0
|
||||
material_symbols_icons: ^4.2872.0
|
||||
drift: ^2.28.1
|
||||
drift_flutter: ^0.2.5
|
||||
path: ^1.9.1
|
||||
@@ -103,8 +103,7 @@ dependencies:
|
||||
gal: ^2.3.2
|
||||
dismissible_page: ^1.0.2
|
||||
super_sliver_list: ^0.4.1
|
||||
flutter_webrtc: ^1.0.0
|
||||
livekit_client: ^2.5.0+hotfix.1
|
||||
livekit_client: ^2.5.0+hotfix.3
|
||||
pasteboard: ^0.4.0
|
||||
flutter_colorpicker: ^1.1.0
|
||||
record: ^6.1.1
|
||||
@@ -114,9 +113,9 @@ dependencies:
|
||||
flutter_popup_card: ^0.0.6
|
||||
timezone: ^0.10.1
|
||||
flutter_timezone: ^4.1.1
|
||||
fl_chart: ^1.0.0
|
||||
fl_chart: ^1.1.0
|
||||
sign_in_with_apple: ^7.0.1
|
||||
flutter_svg: ^2.2.0
|
||||
flutter_svg: ^2.2.1
|
||||
native_exif: ^0.6.2
|
||||
local_auth: ^2.3.0
|
||||
flutter_secure_storage: ^9.2.4
|
||||
@@ -131,15 +130,17 @@ dependencies:
|
||||
mime: ^2.0.0
|
||||
html2md: ^1.3.2
|
||||
flutter_typeahead: ^5.2.0
|
||||
flutter_langdetect: ^0.0.2
|
||||
waveform_flutter: ^1.2.0
|
||||
flutter_app_update: ^3.2.2
|
||||
firebase_crashlytics: ^5.0.0
|
||||
firebase_analytics: ^12.0.0
|
||||
firebase_crashlytics: ^5.0.1
|
||||
firebase_analytics: ^12.0.1
|
||||
material_color_utilities: ^0.11.1
|
||||
screenshot: ^3.0.0
|
||||
flutter_card_swiper: ^7.0.2
|
||||
file_saver: ^0.3.1
|
||||
tray_manager: ^0.5.1
|
||||
flutter_webrtc: ^1.1.0
|
||||
flutter_local_notifications: ^19.4.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@@ -237,4 +238,3 @@ msix_config:
|
||||
msix_version: 3.2.0.0
|
||||
logo_path: .\assets\icons\icon.png
|
||||
capabilities: internetClientServer, location, microphone, webcam
|
||||
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <super_native_extensions/super_native_extensions_plugin_c_api.h>
|
||||
#include <tray_manager/tray_manager_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
#include <volume_controller/volume_controller_plugin_c_api.h>
|
||||
|
||||
@@ -76,6 +77,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||
SuperNativeExtensionsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("SuperNativeExtensionsPluginCApi"));
|
||||
TrayManagerPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("TrayManagerPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
VolumeControllerPluginCApiRegisterWithRegistrar(
|
||||
|
@@ -25,12 +25,14 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
share_plus
|
||||
sqlite3_flutter_libs
|
||||
super_native_extensions
|
||||
tray_manager
|
||||
url_launcher_windows
|
||||
volume_controller
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
croppy
|
||||
flutter_local_notifications_windows
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
Reference in New Issue
Block a user