Compare commits
234 Commits
Author | SHA1 | Date | |
---|---|---|---|
107379d9fe | |||
0d807b8708 | |||
ac1b3fe15c | |||
5853de32a2 | |||
eac1be365e | |||
3fb1d7a6d4 | |||
0480b5244f | |||
56fb92c6b9 | |||
b3267f0026 | |||
88587c10da | |||
9012566dbf | |||
6e00a99803 | |||
aa17a5d52a | |||
ebeffbe1aa | |||
d22eac5c10 | |||
e5381dd5e0 | |||
1c26944a05 | |||
df787f02a1 | |||
db43b7dca5 | |||
59c4d667f6 | |||
063c087089 | |||
48e3b510cf | |||
77288713e1 | |||
1abc65f8fa | |||
a6b17f2c05 | |||
d8dd4060c0 | |||
c8e131c1ab | |||
f4621dd2b4 | |||
6e442c144e | |||
8bbd964026 | |||
0b8a5a3303 | |||
65c6083640 | |||
ad7a34ec18 | |||
6c32d76f78 | |||
2aa699547c | |||
1f4aa8916d | |||
e2c2e41f89 | |||
0f2b854e45 | |||
c21ca5573c | |||
1809f2557d | |||
1fc84099fe | |||
f8755f5220 | |||
4041d6dc4e | |||
cc1071d86e | |||
e334b862df | |||
32c33a963a | |||
a04bfe4cf9 | |||
7b7988e6cb | |||
81a616157e | |||
52312662fb | |||
ca18d6ade4 | |||
af7cc8dab0 | |||
382e3c4a4c | |||
1e37c6ddae | |||
442ef06147 | |||
606a0d708a | |||
558828f3e0 | |||
09dc7d2a0d | |||
6876d2e7c0 | |||
3a5964730c | |||
271c722df3 | |||
97656249f2 | |||
d7e6fe2d8f | |||
2e9c4d166e | |||
c5258cb9ca | |||
47c535910d | |||
66f2f33394 | |||
f5fbe1f483 | |||
fcf4dc7a2d | |||
43b7059957 | |||
11c913af60 | |||
db8f0d63e1 | |||
4036a79995 | |||
859bbd09e0 | |||
60033fdef3 | |||
9c3d181deb | |||
9e6829bd5a | |||
f50461a7f7 | |||
147879e4d8 | |||
f353c05cb5 | |||
ac60043ca7 | |||
8d79274b0c | |||
ad4e4071fa | |||
c59f77c877 | |||
16047a7d57 | |||
fdc68fc5e1 | |||
bbee825cf4 | |||
2673c11046 | |||
3ac6822ab6 | |||
7a5fd2e468 | |||
e1ddd22e4e | |||
22b2ae32e9 | |||
9d5c452eae | |||
0fdb1e4ead | |||
724bd6592e | |||
2d347e0d41 | |||
de39799301 | |||
4b921602a2 | |||
6cde218393 | |||
c896185af0 | |||
4cbeafd447 | |||
91a32e6736 | |||
befc647b03 | |||
16b2e3a0c7 | |||
0cc842c030 | |||
fb370a484d | |||
153c15e5c9 | |||
6a0f42cdc9 | |||
01aaa5455e | |||
f3ceb5f967 | |||
b5e2fa4c25 | |||
8378024490 | |||
6d40d6bba3 | |||
77075c8dab | |||
dec34e297d | |||
358677ade0 | |||
d2f37ae45d | |||
e4b741ff0c | |||
e69abb7f9d | |||
565a8e41cc | |||
c9fbe47337 | |||
01db63e297 | |||
d87e67bd17 | |||
06aa1fb359 | |||
62733bf29f | |||
ce16de9c71 | |||
47eb6cbc66 | |||
029e72fb0b | |||
152efd97a0 | |||
ad1dc064e6 | |||
675b5dea5d | |||
5941cb9fd5 | |||
e11bf204af | |||
8a2d94cedf | |||
780f7c22bc | |||
c18ce88993 | |||
73456fcff6 | |||
8e8be52658 | |||
df22b65777 | |||
1437414b7f | |||
c1ff317c66 | |||
f3375070a0 | |||
204df3306e | |||
aeaade9590 | |||
306ce9e2b4 | |||
a487924300 | |||
ad66c11593 | |||
40b885b27b | |||
2183a2ca55 | |||
00449f3f83 | |||
b14e55355f | |||
db808650e3 | |||
c1cbcbe734 | |||
2c4040096f | |||
b449735bf5 | |||
dd01f964d4 | |||
6daa04c208 | |||
19ec0a7ede | |||
f3b2a2a0ac | |||
bba38e6845 | |||
408a2489e2 | |||
133213b430 | |||
2ff142a84f | |||
e385f79df2 | |||
8d9a8b5435 | |||
c5a975b5ed | |||
1210cda998 | |||
3b56b94242 | |||
34043e722b | |||
e4a5ac9d0a | |||
c991590b27 | |||
d8b2c7f81e | |||
1fd042bcae | |||
0a04c72468 | |||
4e8f2ddef3 | |||
85f97521e5 | |||
9c451f485a | |||
f836b22c73 | |||
18fba0c9e7 | |||
c68138e516 | |||
cedd0b083a | |||
1a0721ba3a | |||
a75f42e440 | |||
e4a6ff2da4 | |||
baa6b401d3 | |||
bd1369e72d | |||
10520b4448 | |||
cab2217793 | |||
4e4e551e2f | |||
597a8a802a | |||
fff756cbe0 | |||
e38778dbf9 | |||
cc9081b011 | |||
14e8f7b775 | |||
a70e6c7118 | |||
48ca885a2c | |||
09cb340a9d | |||
b6ebd6bef6 | |||
2ec25fd1a2 | |||
bc99865ba8 | |||
f834351ce2 | |||
0f1a02f65b | |||
6ad0a34645 | |||
fdc71475fc | |||
047defebd1 | |||
6148e889aa | |||
1d7affcd84 | |||
cc1e0599aa | |||
221b97901f | |||
498bb0e5fb | |||
aa94dfcfe0 | |||
65d9253876 | |||
3ac510c4b1 | |||
253cd1ecbd | |||
c82c48dfec | |||
433beec2dd | |||
3a1e7537dd | |||
9170ae6be7 | |||
a5ee5b7f09 | |||
32e6658f3d | |||
e45d9b39d5 | |||
cf1cfecb08 | |||
95ea3e558f | |||
0006a94632 | |||
7ea18dbe12 | |||
6004b74724 | |||
4d82ae8058 | |||
7fe26d0df0 | |||
80bade0e03 | |||
b63db7fe76 | |||
49f73f5f04 | |||
98749f42c0 | |||
f0e6bd64f4 | |||
3bea3a114a |
13
.roadsignrc
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"sync": {
|
||||
"region": "solian",
|
||||
"configPath": "roadsign.toml"
|
||||
},
|
||||
"deployments": [
|
||||
{
|
||||
"region": "solian",
|
||||
"site": "solian-web",
|
||||
"path": "build/web"
|
||||
}
|
||||
]
|
||||
}
|
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"annvisery"
|
||||
]
|
||||
}
|
@ -1,17 +1,18 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-feature android:name="android.hardware.camera"/>
|
||||
<uses-feature android:name="android.hardware.camera.autofocus"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="dev.solsynth.solian">
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
@ -19,37 +20,46 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:label="Solian"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true">
|
||||
android:label="Solian"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:usesCleartextTraffic="true">
|
||||
<receiver android:exported="false"
|
||||
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver"/>
|
||||
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
|
||||
<receiver android:exported="false"
|
||||
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
|
||||
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
|
||||
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="solink" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@ -58,29 +68,33 @@
|
||||
<data android:host="sn.solsynth.dev" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="solink" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
|
||||
|
||||
<service
|
||||
android:name="id.flutter.flutter_background_service.BackgroundService"
|
||||
android:foregroundServiceType="remoteMessaging"
|
||||
/>
|
||||
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2"/>
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
@ -89,8 +103,8 @@
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
</manifest>
|
BIN
android/app/src/main/ic_launcher-playstore.png
Normal file
After Width: | Height: | Size: 125 KiB |
BIN
android/app/src/main/res/drawable-hdpi/splash.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
android/app/src/main/res/drawable-mdpi/splash.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
android/app/src/main/res/drawable-night-v21/background.png
Normal file
After Width: | Height: | Size: 69 B |
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
BIN
android/app/src/main/res/drawable-night/background.png
Normal file
After Width: | Height: | Size: 69 B |
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
BIN
android/app/src/main/res/drawable-v21/background.png
Normal file
After Width: | Height: | Size: 69 B |
@ -1,12 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
BIN
android/app/src/main/res/drawable-xhdpi/splash.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
android/app/src/main/res/drawable-xxhdpi/splash.png
Normal file
After Width: | Height: | Size: 233 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/splash.png
Normal file
After Width: | Height: | Size: 355 KiB |
BIN
android/app/src/main/res/drawable/background.png
Normal file
After Width: | Height: | Size: 69 B |
@ -1,12 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 5.7 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 3.1 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 8.7 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 9.4 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 16 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 18 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 24 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 26 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 17 KiB |
19
android/app/src/main/res/values-night-v31/styles.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -5,6 +5,10 @@
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
|
19
android/app/src/main/res/values-v31/styles.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
@ -5,6 +5,10 @@
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
|
@ -4,3 +4,4 @@ android.enableJetifier=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
kotlin.jvm.target.validation.mode = IGNORE
|
||||
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
||||
|
@ -18,7 +18,7 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version '8.4.0' apply false
|
||||
id "com.android.application" version '8.6.0' apply false
|
||||
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||
id "com.google.firebase.crashlytics" version "2.8.1" apply false
|
||||
id "org.jetbrains.kotlin.android" version '2.0.0' apply false
|
||||
|
358
assets/highlighting/cpp.json
Normal file
@ -0,0 +1,358 @@
|
||||
{
|
||||
"name": "C++",
|
||||
"version": "1.0.0",
|
||||
"fileTypes": ["cpp", "hpp", "cc", "h"],
|
||||
"scopeName": "source.cpp",
|
||||
|
||||
"foldingStartMarker": "\\{\\s*$",
|
||||
"foldingStopMarker": "^\\s*\\}",
|
||||
|
||||
"patterns": [
|
||||
{
|
||||
"name": "meta.preprocessor.script.cpp",
|
||||
"match": "^\\s*#\\s*(include|define|if|ifdef|ifndef|else|endif|pragma)\\b"
|
||||
},
|
||||
{
|
||||
"name": "meta.declaration.cpp",
|
||||
"begin": "^\\w*\\b(namespace|class|struct|enum|typedef|template)\\b",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "keyword.other.declaration.cpp"
|
||||
}
|
||||
},
|
||||
"end": "(\\{|;)",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.terminator.cpp"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"name": "keyword.other.cpp",
|
||||
"match": "\\b(public|private|protected|virtual|override|final)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"include": "#punctuation"
|
||||
},
|
||||
{
|
||||
"include": "#annotations"
|
||||
},
|
||||
{
|
||||
"include": "#keywords"
|
||||
},
|
||||
{
|
||||
"include": "#constants-and-special-vars"
|
||||
},
|
||||
{
|
||||
"include": "#operators"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
}
|
||||
],
|
||||
|
||||
"repository": {
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.empty.cpp",
|
||||
"match": "/\\*\\*/",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.cpp"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": "#comments-doc-oldschool"
|
||||
},
|
||||
{
|
||||
"include": "#comments-doc"
|
||||
},
|
||||
{
|
||||
"include": "#comments-inline"
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-doc-oldschool": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.documentation.cpp",
|
||||
"begin": "/\\*\\*",
|
||||
"end": "\\*/",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments-doc-oldschool"
|
||||
},
|
||||
{
|
||||
"include": "#comments-block"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-doc": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.documentation.cpp",
|
||||
"begin": "///",
|
||||
"while": "^\\s*///",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments-inline"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-inline": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments-block"
|
||||
},
|
||||
{
|
||||
"match": "(//.*)$",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "comment.line.double-slash.cpp"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-block": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.cpp",
|
||||
"begin": "/\\*",
|
||||
"end": "\\*/",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments-block"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"annotations": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "storage.type.annotation.cpp",
|
||||
"match": "__attribute__\\(\\w+\\)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"constants-and-special-vars": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.language.cpp",
|
||||
"match": "\\b(true|false|nullptr)\\b"
|
||||
},
|
||||
{
|
||||
"name": "variable.language.cpp",
|
||||
"match": "\\b(this|super)\\b"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.cpp",
|
||||
"match": "\\b((0(x|X)[0-9a-fA-F]+)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?)\\b"
|
||||
},
|
||||
{
|
||||
"include": "#class-identifier"
|
||||
},
|
||||
{
|
||||
"include": "#function-identifier"
|
||||
}
|
||||
]
|
||||
},
|
||||
"class-identifier": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\b(bool|int|char|double|float|long|short|signed|unsigned|void)\\b",
|
||||
"name": "storage.type.primitive.cpp"
|
||||
},
|
||||
{
|
||||
"begin": "(\\b[A-Z]\\w*\\b)",
|
||||
"end": "(?!<)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "support.class.cpp"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#type-args"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"function-identifier": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\b([a-z_][a-zA-Z0-9_]*)\\s*\\(",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "entity.name.function.cpp"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type-args": {
|
||||
"begin": "(<)",
|
||||
"end": "(>)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "other.source.cpp"
|
||||
}
|
||||
},
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "other.source.cpp"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#class-identifier"
|
||||
},
|
||||
{
|
||||
"match": ","
|
||||
},
|
||||
{
|
||||
"name": "keyword.declaration.cpp",
|
||||
"match": "extends"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
}
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.control.cpp",
|
||||
"match": "\\b(if|else|for|while|do|switch|case|break|continue|goto|return)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.cpp",
|
||||
"match": "\\b(sizeof|typeid|decltype|new|delete)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.try.cpp",
|
||||
"match": "\\b(try|catch|throw)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.cpp",
|
||||
"match": "\\b(static|inline|virtual|override|const|volatile|explicit|friend|constexpr)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"operators": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.operator.comparison.cpp",
|
||||
"match": "(==|!=|<=?|>=?)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.arithmetic.cpp",
|
||||
"match": "(\\+|\\-|\\*|\\/|%)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.cpp",
|
||||
"match": "(=|\\+=|-=|\\*=|/=|%=)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.logical.cpp",
|
||||
"match": "(\\&\\&|\\|\\||!)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.bitwise.cpp",
|
||||
"match": "(<<|>>|\\&|\\||\\^|~)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"string-interp": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\$([a-zA-Z0-9_]+)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "variable.parameter.cpp"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "string.interpolated.expression.cpp",
|
||||
"begin": "\\$\\{",
|
||||
"end": "\\}",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#constants-and-special-vars",
|
||||
"name": "variable.parameter.cpp"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
{
|
||||
"name": "variable.parameter.cpp",
|
||||
"match": "[a-zA-Z0-9_]+"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "constant.character.escape.cpp",
|
||||
"match": "\\\\."
|
||||
}
|
||||
]
|
||||
},
|
||||
"strings": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.quoted.double.cpp",
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.cpp",
|
||||
"match": "\\\\."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.single.cpp",
|
||||
"begin": "'",
|
||||
"end": "'",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.cpp",
|
||||
"match": "\\\\."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"punctuation": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "punctuation.comma.cpp",
|
||||
"match": ","
|
||||
},
|
||||
{
|
||||
"name": "punctuation.terminator.cpp",
|
||||
"match": ";"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
531
assets/highlighting/dart.json
Normal file
@ -0,0 +1,531 @@
|
||||
{
|
||||
"name": "Dart",
|
||||
"version": "1.2.3",
|
||||
"fileTypes": ["dart"],
|
||||
"scopeName": "source.dart",
|
||||
|
||||
"foldingStartMarker": "\\{\\s*$",
|
||||
"foldingStopMarker": "^\\s*\\}",
|
||||
|
||||
"patterns": [
|
||||
{
|
||||
"name": "meta.preprocessor.script.dart",
|
||||
"match": "^(#!.*)$"
|
||||
},
|
||||
{
|
||||
"name": "meta.declaration.dart",
|
||||
"begin": "^\\w*\\b(library|import|part of|part|export)\\b",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "keyword.other.import.dart"
|
||||
}
|
||||
},
|
||||
"end": ";",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.terminator.dart"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"name": "keyword.other.import.dart",
|
||||
"match": "\\b(as|show|hide)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.dart",
|
||||
"match": "\\b(if)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"include": "#punctuation"
|
||||
},
|
||||
{
|
||||
"include": "#annotations"
|
||||
},
|
||||
{
|
||||
"include": "#keywords"
|
||||
},
|
||||
{
|
||||
"include": "#constants-and-special-vars"
|
||||
},
|
||||
{
|
||||
"include": "#operators"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
}
|
||||
],
|
||||
|
||||
"repository": {
|
||||
"dartdoc": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "(\\[.*?\\])",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.name.source.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": "^ {4,}(?![ \\*]).*",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.name.source.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"contentName": "variable.other.source.dart",
|
||||
"begin": "```.*?$",
|
||||
"end": "```"
|
||||
},
|
||||
{
|
||||
"match": "(`.*?`)",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.source.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": "(`.*?`)",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.source.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": "(\\* (( ).*))$",
|
||||
"captures": {
|
||||
"2": {
|
||||
"name": "variable.other.source.dart"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.empty.dart",
|
||||
"match": "/\\*\\*/",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": "#comments-doc-oldschool"
|
||||
},
|
||||
{
|
||||
"include": "#comments-doc"
|
||||
},
|
||||
{
|
||||
"include": "#comments-inline"
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-doc-oldschool": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.documentation.dart",
|
||||
"begin": "/\\*\\*",
|
||||
"end": "\\*/",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments-doc-oldschool"
|
||||
},
|
||||
{
|
||||
"include": "#comments-block"
|
||||
},
|
||||
{
|
||||
"include": "#dartdoc"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-doc": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.documentation.dart",
|
||||
"begin": "///",
|
||||
"while": "^\\s*///",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#dartdoc"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-inline": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments-block"
|
||||
},
|
||||
{
|
||||
"match": "((//).*)$",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "comment.line.double-slash.dart"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments-block": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.dart",
|
||||
"begin": "/\\*",
|
||||
"end": "\\*/",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments-block"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"annotations": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "storage.type.annotation.dart",
|
||||
"match": "@[a-zA-Z]+"
|
||||
}
|
||||
]
|
||||
},
|
||||
"constants-and-special-vars": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.language.dart",
|
||||
"match": "(?<!\\$)\\b(true|false|null)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "variable.language.dart",
|
||||
"match": "(?<!\\$)\\b(this|super)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.dart",
|
||||
"match": "(?<!\\$)\\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"include": "#class-identifier"
|
||||
},
|
||||
{
|
||||
"include": "#function-identifier"
|
||||
}
|
||||
]
|
||||
},
|
||||
"class-identifier": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "(?<!\\$)\\b(bool|num|int|double|dynamic)\\b(?!\\$)",
|
||||
"name": "support.class.dart"
|
||||
},
|
||||
{
|
||||
"match": "(?<!\\$)\\bvoid\\b(?!\\$)",
|
||||
"name": "storage.type.primitive.dart"
|
||||
},
|
||||
{
|
||||
"begin": "(?<![a-zA-Z0-9_$])([_$]*[A-Z][a-zA-Z0-9_$]*)\\b",
|
||||
"end": "(?!<)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "support.class.dart"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#type-args"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"function-identifier": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "([_$]*[a-z][a-zA-Z0-9_$]*)(<(?:[a-zA-Z0-9_$<>?]|,\\s*|\\s+extends\\s+)+>)?[!?]?\\(",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "entity.name.function.dart"
|
||||
},
|
||||
"2": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#type-args"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type-args": {
|
||||
"begin": "(<)",
|
||||
"end": "(>)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "other.source.dart"
|
||||
}
|
||||
},
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "other.source.dart"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#class-identifier"
|
||||
},
|
||||
{
|
||||
"match": ","
|
||||
},
|
||||
{
|
||||
"name": "keyword.declaration.dart",
|
||||
"match": "extends"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
}
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.cast.dart",
|
||||
"match": "(?<!\\$)\\bas\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.catch-exception.dart",
|
||||
"match": "(?<!\\$)\\b(try|on|catch|finally|throw|rethrow)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.dart",
|
||||
"match": "(?<!\\$)\\b(break|case|continue|default|do|else|for|if|in|return|switch|while|when)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.dart",
|
||||
"match": "(?<!\\$)\\b(sync(\\*)?|async(\\*)?|await|yield(\\*)?)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.dart",
|
||||
"match": "(?<!\\$)\\bassert\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.new.dart",
|
||||
"match": "(?<!\\$)\\b(new)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.declaration.dart",
|
||||
"match": "(?<!\\$)\\b(abstract|sealed|base|interface|class|enum|extends|extension type|extension|external|factory|implements|get(?!\\()|mixin|native|operator|set(?!\\()|typedef|with|covariant)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "storage.modifier.dart",
|
||||
"match": "(?<!\\$)\\b(static|final|const|required|late)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "storage.type.primitive.dart",
|
||||
"match": "(?<!\\$)\\b(?:void|var)\\b(?!\\$)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"operators": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.operator.dart",
|
||||
"match": "(?<!\\$)\\b(is\\!?)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.ternary.dart",
|
||||
"match": "\\?|:"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.bitwise.dart",
|
||||
"match": "(<<|>>>?|~|\\^|\\||&)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.bitwise.dart",
|
||||
"match": "((&|\\^|\\||<<|>>>?)=)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.closure.dart",
|
||||
"match": "(=>)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.comparison.dart",
|
||||
"match": "(==|!=|<=?|>=?)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.arithmetic.dart",
|
||||
"match": "(([+*/%-]|\\~)=)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.dart",
|
||||
"match": "(=)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.increment-decrement.dart",
|
||||
"match": "(\\-\\-|\\+\\+)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.arithmetic.dart",
|
||||
"match": "(\\-|\\+|\\*|\\/|\\~\\/|%)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.logical.dart",
|
||||
"match": "(!|&&|\\|\\|)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"string-interp": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\$([a-zA-Z0-9_]+)",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "variable.parameter.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "string.interpolated.expression.dart",
|
||||
"begin": "\\$\\{",
|
||||
"end": "\\}",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#constants-and-special-vars",
|
||||
"name": "variable.parameter.dart"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
{
|
||||
"name": "variable.parameter.dart",
|
||||
"match": "[a-zA-Z0-9_]+"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "constant.character.escape.dart",
|
||||
"match": "\\\\."
|
||||
}
|
||||
]
|
||||
},
|
||||
"strings": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.interpolated.triple.double.dart",
|
||||
"begin": "(?<!r)\"\"\"",
|
||||
"end": "\"\"\"(?!\")",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#string-interp"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.interpolated.triple.single.dart",
|
||||
"begin": "(?<!r)'''",
|
||||
"end": "'''(?!')",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#string-interp"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.triple.double.dart",
|
||||
"begin": "r\"\"\"",
|
||||
"end": "\"\"\"(?!\")"
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.triple.single.dart",
|
||||
"begin": "r'''",
|
||||
"end": "'''(?!')"
|
||||
},
|
||||
{
|
||||
"name": "string.interpolated.double.dart",
|
||||
"begin": "(?<!\\|r)\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "invalid.string.newline",
|
||||
"match": "\\n"
|
||||
},
|
||||
{
|
||||
"include": "#string-interp"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.double.dart",
|
||||
"begin": "r\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "invalid.string.newline",
|
||||
"match": "\\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.interpolated.single.dart",
|
||||
"begin": "(?<!\\|r)'",
|
||||
"end": "'",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "invalid.string.newline",
|
||||
"match": "\\n"
|
||||
},
|
||||
{
|
||||
"include": "#string-interp"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.single.dart",
|
||||
"begin": "r'",
|
||||
"end": "'",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "invalid.string.newline",
|
||||
"match": "\\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"punctuation": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "punctuation.comma.dart",
|
||||
"match": ","
|
||||
},
|
||||
{
|
||||
"name": "punctuation.terminator.dart",
|
||||
"match": ";"
|
||||
},
|
||||
{
|
||||
"name": "punctuation.dot.dart",
|
||||
"match": "\\."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
212
assets/highlighting/json.json
Normal file
@ -0,0 +1,212 @@
|
||||
{
|
||||
"fileTypes": ["json"],
|
||||
"foldingStartMarker": "^\\s*[{\\[](?!.*[}\\]],?\\s*$)|[{\\[]\\s*$",
|
||||
"foldingStopMarker": "^\\s*[}\\]]",
|
||||
"keyEquivalent": "^~J",
|
||||
"name": "JSON (Javascript Next)",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#value"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"array": {
|
||||
"begin": "\\[",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.array.begin.json"
|
||||
}
|
||||
},
|
||||
"end": "\\]",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.array.end.json"
|
||||
}
|
||||
},
|
||||
"name": "meta.structure.array.json",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#value"
|
||||
},
|
||||
{
|
||||
"match": ",",
|
||||
"name": "punctuation.separator.array.json"
|
||||
},
|
||||
{
|
||||
"match": "[^\\s\\]]",
|
||||
"name": "invalid.illegal.expected-array-separator.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "/\\*\\*",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.json"
|
||||
}
|
||||
},
|
||||
"end": "\\*/",
|
||||
"name": "comment.block.documentation.json"
|
||||
},
|
||||
{
|
||||
"begin": "/\\*",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.json"
|
||||
}
|
||||
},
|
||||
"end": "\\*/",
|
||||
"name": "comment.block.json"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.json"
|
||||
}
|
||||
},
|
||||
"match": "(//).*$\\n?",
|
||||
"name": "comment.line.double-slash.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
"constant": {
|
||||
"match": "\\b(?:true|false|null)\\b",
|
||||
"name": "constant.language.json"
|
||||
},
|
||||
"number": {
|
||||
"match": "-?(?:0|[1-9]\\d*)\n(?:\n(?:\n\\.\\d+)?\n(?:\n[eE][+-]?\\d+)?)?",
|
||||
"name": "constant.numeric.json"
|
||||
},
|
||||
"object": {
|
||||
"begin": "\\{",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.dictionary.begin.json"
|
||||
}
|
||||
},
|
||||
"end": "\\}",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.dictionary.end.json"
|
||||
}
|
||||
},
|
||||
"name": "meta.structure.dictionary.json",
|
||||
"patterns": [
|
||||
{
|
||||
"comment": "the JSON object key",
|
||||
"include": "#objectkey"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"begin": ":",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.separator.dictionary.key-value.json"
|
||||
}
|
||||
},
|
||||
"end": "(,)|(?=\\})",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.separator.dictionary.pair.json"
|
||||
}
|
||||
},
|
||||
"name": "meta.structure.dictionary.value.json",
|
||||
"patterns": [
|
||||
{
|
||||
"comment": "the JSON object value",
|
||||
"include": "#value"
|
||||
},
|
||||
{
|
||||
"match": "[^\\s,]",
|
||||
"name": "invalid.illegal.expected-dictionary-separator.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": "[^\\s\\}]",
|
||||
"name": "invalid.illegal.expected-dictionary-separator.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"string": {
|
||||
"begin": "\"",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.begin.json"
|
||||
}
|
||||
},
|
||||
"end": "\"",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.json"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.double.json",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#stringcontent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"objectkey": {
|
||||
"begin": "\"",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.support.type.property-name.begin.json"
|
||||
}
|
||||
},
|
||||
"end": "\"",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.support.type.property-name.end.json"
|
||||
}
|
||||
},
|
||||
"name": "support.type.property-name.json",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#stringcontent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"stringcontent": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\\\(?:[\"\\\\/bfnrt]|u[0-9a-fA-F]{4})",
|
||||
"name": "constant.character.escape.json"
|
||||
},
|
||||
{
|
||||
"match": "\\\\.",
|
||||
"name": "invalid.illegal.unrecognized-string-escape.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#constant"
|
||||
},
|
||||
{
|
||||
"include": "#number"
|
||||
},
|
||||
{
|
||||
"include": "#string"
|
||||
},
|
||||
{
|
||||
"include": "#array"
|
||||
},
|
||||
{
|
||||
"include": "#object"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scopeName": "source.json",
|
||||
"uuid": "8f97457b-516e-48ce-83c7-08ae12fb327a"
|
||||
}
|
98
assets/highlighting/python.json
Normal file
@ -0,0 +1,98 @@
|
||||
{
|
||||
"name": "Python",
|
||||
"version": "1.0.0",
|
||||
"fileTypes": ["py"],
|
||||
"scopeName": "source.python",
|
||||
"foldingStartMarker": "\\b(?:def|class)\\s*[^:]*:\\s*$",
|
||||
"foldingStopMarker": "^\\s*\\}",
|
||||
"patterns": [
|
||||
{ "include": "#comments" },
|
||||
{ "include": "#keywords" },
|
||||
{ "include": "#constants-and-special-vars" },
|
||||
{ "include": "#operators" },
|
||||
{ "include": "#strings" }
|
||||
],
|
||||
"repository": {
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{ "name": "comment.line.hash.python", "match": "#.*$" },
|
||||
{ "name": "comment.block.python", "begin": "'''", "end": "'''" },
|
||||
{ "name": "comment.block.python", "begin": "\"\"\"", "end": "\"\"\"" }
|
||||
]
|
||||
},
|
||||
"keywords": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.control.python",
|
||||
"match": "\\b(?:if|else|while|for|in|break|continue|return)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.logical.python",
|
||||
"match": "\\b(?:and|or|not)\\b"
|
||||
},
|
||||
{ "name": "keyword.operator.assignment.python", "match": "=" },
|
||||
{ "name": "storage.modifier.python", "match": "\\b(?:def|class)\\b" }
|
||||
]
|
||||
},
|
||||
"constants-and-special-vars": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.language.python",
|
||||
"match": "\\b(?:True|False|None)\\b"
|
||||
},
|
||||
{ "name": "variable.language.python", "match": "\\b(?:self)\\b" },
|
||||
{
|
||||
"name": "constant.numeric.python",
|
||||
"match": "\\b(?:\\d+\\.?\\d*|\\.\\d+)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"operators": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "keyword.operator.arithmetic.python",
|
||||
"match": "\\b(?:\\+|-|\\*|/|%|//)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.comparison.python",
|
||||
"match": "\\b(?:==|!=|<|<=|>|>=)\\b"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.logical.python",
|
||||
"match": "\\b(?:and|or|not)\\b"
|
||||
}
|
||||
]
|
||||
},
|
||||
"strings": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "string.quoted.triple.double.python",
|
||||
"begin": "\"\"\"",
|
||||
"end": "\"\"\""
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.triple.single.python",
|
||||
"begin": "'''",
|
||||
"end": "'''"
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.double.python",
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"patterns": [{ "include": "#string-escape" }]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.single.python",
|
||||
"begin": "'",
|
||||
"end": "'",
|
||||
"patterns": [{ "include": "#string-escape" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
"string-escape": {
|
||||
"patterns": [
|
||||
{ "name": "constant.character.escape.python", "match": "\\\\[\"']" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
145
assets/highlighting/sql.json
Normal file
@ -0,0 +1,145 @@
|
||||
{
|
||||
"fileTypes": ["sql", "ddl", "dml"],
|
||||
"foldingStartMarker": "(?i)^\\s*(begin|if|loop)\\b",
|
||||
"foldingStopMarker": "(?i)^\\s*(end)\\b",
|
||||
"keyEquivalent": "^~S",
|
||||
"name": "PL/pgSQL (Postgres)",
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "/\\*",
|
||||
"end": "\\*/",
|
||||
"name": "comment.block.postgres"
|
||||
},
|
||||
{
|
||||
"match": "--.*$",
|
||||
"name": "comment.line.double-dash.postgres"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.postgres"
|
||||
},
|
||||
"2": {
|
||||
"name": "keyword.other.postgres"
|
||||
}
|
||||
},
|
||||
"match": "(?i)^\\s*(create)(\\s+or\\s+replace)?\\s+",
|
||||
"name": "meta.create.postgres"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.postgres"
|
||||
},
|
||||
"2": {
|
||||
"name": "keyword.other.postgres"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.type.postgres"
|
||||
}
|
||||
},
|
||||
"match": "(?i)\\b(package)(\\s+body)?\\s+(\\S+)",
|
||||
"name": "meta.package.postgres"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.postgres"
|
||||
},
|
||||
"2": {
|
||||
"name": "entity.name.type.postgres"
|
||||
}
|
||||
},
|
||||
"match": "(?i)\\b(type)\\s+\"([^\"]+)\"",
|
||||
"name": "meta.type.postgres"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.postgres"
|
||||
},
|
||||
"2": {
|
||||
"name": "entity.name.function.postgres"
|
||||
}
|
||||
},
|
||||
"match": "(?i)\\s*(function|procedure)\\s+([-a-z0-9_.]+)",
|
||||
"name": "meta.procedure.postgres"
|
||||
},
|
||||
{
|
||||
"match": "[!<>:]?=|<>|<|>|\\+|(?<!\\.)\\*|-|(?<!^)/|@@|\\|\\|",
|
||||
"name": "keyword.operator.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(true|false|null|found)\\b",
|
||||
"name": "constant.language.postgres"
|
||||
},
|
||||
{
|
||||
"match": "\\b\\d+(\\.\\d+)?\\b",
|
||||
"name": "constant.numeric.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(if|elsif|else|end\\s+if|loop|end\\s+loop|for|foreach|array|case|end\\s+case|continue|return|goto|alias)\\b",
|
||||
"name": "keyword.control.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(or|and|not|like)\\b",
|
||||
"name": "keyword.operator.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(sysdate|%(isopen|found|notfound|rowcount)|commit|rollback|sqlerrm|substr|cast|decode|length|lower|upper|coalesce)\\b",
|
||||
"name": "support.function.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(avg|count|sum|max|min|nvl|trim|to_date|to_char|lpad|ltrim|rpad|rtrim|trunc|to_number|regexp_split_to_array|regexp_replace)\\b",
|
||||
"name": "support.function.builtin.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(sql|sqlcode)\\b",
|
||||
"name": "variable.language.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(p(i|o|io)_[-a-z0-9_]+)\\b",
|
||||
"name": "variable.parameter.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(l_[-a-z0-9_]+)\\b",
|
||||
"name": "variable.other.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(immutable|volatile|stable|serial|primary|key|references|comment|column|schema|authorization|get|diagnostics|returning|drop|all|raise|notice|warning|exception|external|security|definer|language|grant|execute|on|to|function|procedure|returns|end|then|deterministic|exception|when|others|subtype|constant|range|binary_integer|declare|begin|in|out|is|as|exit|open|fetch|into|close|type|rowtype|default|\\.(extend|count|first|last|next|nextval|currval)|cost|alter|owner)\\b",
|
||||
"name": "keyword.other.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(select|perform|from|where|order\\s+by|group\\s+by|asc|desc|update|set|insert|into|values|delete|from|distinct|union|having|limit|table|of|prepare|(inner|left|outer) join)\\b",
|
||||
"name": "keyword.other.sql.postgres"
|
||||
},
|
||||
{
|
||||
"match": "[$][0-9]+",
|
||||
"name": "storage.type.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(dbms_lock|dbms_output)\\b",
|
||||
"name": "support.class.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(put_line)\\b",
|
||||
"name": "support.function.postgres"
|
||||
},
|
||||
{
|
||||
"begin": "'",
|
||||
"end": "'",
|
||||
"name": "string.quoted.single.postgres"
|
||||
},
|
||||
{
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"name": "string.quoted.double.postgres"
|
||||
},
|
||||
{
|
||||
"match": "(?i)\\b(number|integer|bigint|varchar2|varchar|boolean|date|setof|record|query|numeric|void|character varying|text|([-a-z0-9_.]+%(row)?type))\\b",
|
||||
"name": "storage.type.postgres"
|
||||
}
|
||||
],
|
||||
"scopeName": "source.plpgsql.postgres",
|
||||
"uuid": "28DCE4DD-F5E1-4ED3-8847-64DA6B1F9163"
|
||||
}
|
66
assets/highlighting/yaml.json
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "YAML",
|
||||
"fileTypes": ["yaml", "yml"],
|
||||
"scopeName": "source.yaml",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.line.number-sign.yaml",
|
||||
"match": "#.*",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.yaml"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "entity.name.tag.yaml",
|
||||
"match": "^\\s*\\w+",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.tag.yaml"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "punctuation.separator.key-value.yaml",
|
||||
"match": ":",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.separator.key-value.yaml"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.double.yaml",
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.yaml",
|
||||
"match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{6}|.)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.single.yaml",
|
||||
"begin": "'",
|
||||
"end": "'",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "constant.character.escape.yaml",
|
||||
"match": "''"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"scalar-plain": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\b(\\w+)\\b",
|
||||
"name": "scalar.plain.yaml"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
498
assets/locales/en_us.json
Normal file
@ -0,0 +1,498 @@
|
||||
{
|
||||
"done": "Done",
|
||||
"hide": "Hide",
|
||||
"okay": "Okay",
|
||||
"next": "Next",
|
||||
"prev": "Previous",
|
||||
"reset": "Reset",
|
||||
"page": "Page",
|
||||
"home": "Home",
|
||||
"guest": "Guest",
|
||||
"draft": "Draft",
|
||||
"dashboard": "Dashboard",
|
||||
"today": "Today",
|
||||
"yesterday": "Yesterday",
|
||||
"draftSave": "Save",
|
||||
"draftBox": "Draft Box",
|
||||
"more": "More",
|
||||
"share": "Share",
|
||||
"shareNoUri": "Share text content",
|
||||
"alias": "Alias",
|
||||
"feed": "Feed",
|
||||
"explore": "Explore",
|
||||
"posts": "Posts",
|
||||
"unlink": "Unlink",
|
||||
"postSearch": "Search Post",
|
||||
"postSearchWithTag": "Searching with tag #@key",
|
||||
"postSearchWithCategory": "Searching in category @category",
|
||||
"feedUnreadCount": "@count posts you may missed",
|
||||
"messages": "Messages",
|
||||
"messagesUnreadCount": "@count messages unread",
|
||||
"dailySign": "Daily Sign",
|
||||
"dailySignAction": "Sign Today",
|
||||
"dailySignHistoryAction": "View History",
|
||||
"dailySignNone": "You haven't sign today",
|
||||
"dailySignTier0": "Everything may not be good",
|
||||
"dailySignTier1": "Something may be wrong",
|
||||
"dailySignTier2": "Just so so",
|
||||
"dailySignTier3": "Something may goes well",
|
||||
"dailySignTier4": "Everything will be awesome",
|
||||
"dailySignHistoryTitle": "Fortune History",
|
||||
"dailySignHistoryRecent": "Recent Fortune",
|
||||
"dailySignHistoryReward": "Reward Trends",
|
||||
"dashboardFooter": "Don't be serious, just for fun.",
|
||||
"visitProfilePage": "Visit Profile Page",
|
||||
"profilePage": "Page",
|
||||
"profilePosts": "Posts",
|
||||
"profileAlbum": "Album",
|
||||
"chat": "Chat",
|
||||
"apply": "Apply",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"leave": "Leave",
|
||||
"loading": "Loading...",
|
||||
"about": "About",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"insert": "Insert",
|
||||
"settings": "Settings",
|
||||
"settingsNotificationBgService": "Background notification service",
|
||||
"settingsNotificationBgServiceDesc": "A notification service is always installed on the device, so that some devices that do not support push notifications can receive notifications in the background. When this feature is enabled, push notifications will not be registered with the server, and you will always appear to be online in the eyes of others (except for invisible). You may need to turn off power and traffic optimization in the settings.",
|
||||
"search": "Search",
|
||||
"post": "Post",
|
||||
"article": "Article",
|
||||
"reply": "Reply",
|
||||
"repost": "Repost",
|
||||
"openInAlbum": "Open in album",
|
||||
"openInBrowser": "Open in browser",
|
||||
"notification": "Notification",
|
||||
"notificationUnreadCount": "@count unread notifications",
|
||||
"errorHappened": "An error occurred",
|
||||
"errorHappenedUnauthorized": "Unauthorized request, please sign in or try resign in.",
|
||||
"errorHappenedRequestBad": "Request error, the server refused to process the request. Please check your request data.",
|
||||
"errorHappenedRequestForbidden": "Request error, insufficient permissions.",
|
||||
"errorHappenedRequestNotFound": "Request error, the requested data does not exist.",
|
||||
"errorHappenedRequestConnection": "Network request failed. Please check the connection status and service status, then try again.",
|
||||
"errorHappenedRequestUnknown": "Request error, unknown type. Please take a full screenshot of this message and submit feedback.",
|
||||
"forgotPassword": "Forgot password",
|
||||
"email": "Email",
|
||||
"username": "Username",
|
||||
"usernameInputHint": "Also supports email and phone number",
|
||||
"nickname": "Nickname",
|
||||
"password": "Password",
|
||||
"passwordOneTime": "One-time-password",
|
||||
"passwordInputHint": "Forgot your password? Go back to the first step to reset your password",
|
||||
"passwordOneTimeInputHint": "Check your inbox or authorizer for a verification code",
|
||||
"title": "Title",
|
||||
"description": "Description",
|
||||
"birthday": "Birthday",
|
||||
"firstName": "First Name",
|
||||
"lastName": "Last Name",
|
||||
"account": "Account",
|
||||
"accountProfile": "Your profile",
|
||||
"accountProfileApplied": "Account profile has been saved.",
|
||||
"accountStickers": "Stickers",
|
||||
"accountFriend": "Friend",
|
||||
"accountFriendNew": "New friend",
|
||||
"accountFriendNewHint": "Use someone's username to send a request of making friends with them!",
|
||||
"accountFriendPending": "Friend requests",
|
||||
"accountFriendBlocked": "Friend blocklist",
|
||||
"accountFriendListHint": "Swipe left to decline, right to approve",
|
||||
"accountFriendRequestSent": "Friend request sent, waiting for processing...",
|
||||
"accountBlocked": "Account has been blocked",
|
||||
"accountUnblocked": "Account has been unblocked",
|
||||
"accountSuspended": "Account was suspended",
|
||||
"accountSuspendedAt": "Account was suspended since @date",
|
||||
"aspectRatio": "Aspect Ratio",
|
||||
"aspectRatioSquare": "Square",
|
||||
"aspectRatioPortrait": "Portrait",
|
||||
"aspectRatioLandscape": "Landscape",
|
||||
"unsignedIn": "Unsigned in",
|
||||
"signin": "Sign in",
|
||||
"signinRequired": "Sign in",
|
||||
"signinRequiredHint": "Sign in to get full access of Solar Network",
|
||||
"signinGreeting": "Welcome back\nSolar Network",
|
||||
"signinCaption": "Sign in to create post, start a realm, message your friend and more!",
|
||||
"signinRiskDetected": "Risk detected, click Next to open a webpage and signin through it to pass security check.",
|
||||
"signinResetPasswordHint": "Please enter username to request reset password.",
|
||||
"signinResetPasswordSent": "Reset password request sent, check your inbox!",
|
||||
"signinPickFactor": "Pick a way\nfor verification",
|
||||
"signinEnterPassword": "Enter your\npassword",
|
||||
"signinMultiFactor": "@n step(s) verifications",
|
||||
"authFactorEmail": "Email One-time-password",
|
||||
"authFactorPassword": "Password",
|
||||
"signup": "Sign up",
|
||||
"signupGreeting": "Welcome onboard",
|
||||
"signupCaption": "Create an account on Solarpass and then get the access of entire Solar Network!",
|
||||
"signupDone": "Sign up successfully.",
|
||||
"signupDoneCaption": "You successfully created an account on Solar Network. Now go sign in!",
|
||||
"signout": "Sign out",
|
||||
"joinedAt": "Joined at @date",
|
||||
"riskDetection": "Risk Detected",
|
||||
"matureContent": "Mature Content",
|
||||
"matureContentCaption": "The content is rated and may not suitable for everyone to view",
|
||||
"notifyAllRead": "Mark all as read",
|
||||
"notifyEmpty": "All notifications read",
|
||||
"notifyEmptyCaption": "It seems like nothing happened recently",
|
||||
"totalSocialCreditPoints": "Social Credit Points",
|
||||
"totalPostCount": "Posts",
|
||||
"totalUpvote": "Upvote",
|
||||
"totalDownvote": "Downvote",
|
||||
"clear": "Clear",
|
||||
"pinPost": "Pin this post",
|
||||
"unpinPost": "Unpin this post",
|
||||
"postRestoreFromLocal": "Restored",
|
||||
"postAutoSaveAt": "Auto saved at @date",
|
||||
"postCategoriesAndTags": "Categories n' Tags",
|
||||
"postPublishDate": "Publish Date",
|
||||
"postPublishAt": "Publish At",
|
||||
"postPublishedUntil": "Publish Until",
|
||||
"postPublishZone": "Publish Zone",
|
||||
"postPublishZoneNone": "None",
|
||||
"postVisibility": "Visibility",
|
||||
"postVisibilityAll": "Everyone",
|
||||
"postVisibilityFriends": "Friends",
|
||||
"postVisibilitySelected": "Selected visible",
|
||||
"postVisibilityFiltered": "Selected invisible",
|
||||
"postVisibilityNone": "Only me",
|
||||
"postVisibleUsers": "Visible users",
|
||||
"postInvisibleUsers": "Invisible users",
|
||||
"postOverview": "Overview",
|
||||
"postThumbnail": "Thumbnail",
|
||||
"postThumbnailAttachmentNew": "Upload thumbnail",
|
||||
"postThumbnailAttachment": "Attachment serial number",
|
||||
"postPinned": "Pinned",
|
||||
"postListNews": "News",
|
||||
"postListFriends": "Friends",
|
||||
"postListShuffle": "Random",
|
||||
"attachmentThumbnail": "Thumbnail",
|
||||
"attachmentThumbnailAttachmentNew": "Upload thumbnail",
|
||||
"attachmentThumbnailAttachment": "Attachment serial number",
|
||||
"postEditorModeStory": "Post a post",
|
||||
"postEditorModeArticle": "Post an article",
|
||||
"postEditor": "Post editor",
|
||||
"articleEditor": "Create new article",
|
||||
"articleDetail": "Article details",
|
||||
"draftBoxOpen": "Open draft box",
|
||||
"postNew": "Create a new post",
|
||||
"postNewInRealmHint": "Add post in realm @realm",
|
||||
"postAction": "Post",
|
||||
"postEdited": "Edited at @date",
|
||||
"postNewCreated": "Created at @date",
|
||||
"attachmentHint": "@count attachment(s)",
|
||||
"postInRealm": "In @realm",
|
||||
"postDetail": "Post",
|
||||
"postReplies": "Replies",
|
||||
"postPublish": "Post a post",
|
||||
"articlePublish": "Write an article",
|
||||
"articleTitlePlaceholder": "Title",
|
||||
"articleDescriptionPlaceholder": "Description",
|
||||
"articleContentPlaceholder": "Content",
|
||||
"postIdentityNotify": "You will post this post as",
|
||||
"postContentPlaceholder": "What's happened?!",
|
||||
"postTagsPlaceholder": "Tags",
|
||||
"postReaction": "Reactions of the Post",
|
||||
"postActionList": "Actions of Post",
|
||||
"postReplyAction": "Make a reply",
|
||||
"postRepliedNotify": "Replied a post from @username.",
|
||||
"postRepostedNotify": "Reposted a post from @username.",
|
||||
"postInRealmNotify": "You're posting in realm @realm.",
|
||||
"postEditingNotify": "You're editing as post from you.",
|
||||
"postReplyingNotify": "You're replying a post from @username.",
|
||||
"postRepostingNotify": "You're reposting a post from @username.",
|
||||
"postDeletionConfirm": "Confirm post deletion",
|
||||
"postDeletionConfirmCaption": "Are your sure to delete post \"@content\"? This action cannot be undone!",
|
||||
"reactAdd": "React",
|
||||
"reactCompleted": "Your reaction has been added",
|
||||
"reactUncompleted": "Your reaction has been removed",
|
||||
"attachmentUploadBy": "Upload by",
|
||||
"attachmentAutoUpload": "Auto Upload",
|
||||
"attachmentUploadQueue": "Upload Queue",
|
||||
"attachmentUploadQueueStart": "Start All",
|
||||
"attachmentUploadInProgress": "There are attachments being uploaded. Please wait until all attachments have been uploaded before proceeding...",
|
||||
"attachmentAttached": "Exists Files",
|
||||
"attachmentUploadBlocked": "Upload blocked, there is currently a task in progress...",
|
||||
"attachmentAdd": "Attach file",
|
||||
"attachmentAddGalleryPhoto": "Gallery photo",
|
||||
"attachmentAddGalleryVideo": "Gallery video",
|
||||
"attachmentAddCameraPhoto": "Capture photo",
|
||||
"attachmentAddCameraVideo": "Capture video",
|
||||
"attachmentAddClipboard": "Paste file",
|
||||
"attachmentAddFile": "Attach file",
|
||||
"attachmentAddLink": "Link attachments",
|
||||
"attachmentAddLinkHint": "Enter attachment serial number to link that attachment",
|
||||
"attachmentAddLinkInput": "Serial number",
|
||||
"attachmentSetting": "Adjust attachment",
|
||||
"attachmentAlt": "Alternative text",
|
||||
"attachmentLoadFailed": "Load Attachment Failed",
|
||||
"attachmentLoadFailedCaption": "Something went wrong during loading the attachment metadata...",
|
||||
"attachmentUploading": "Uploading @name...",
|
||||
"attachmentUploadingWebMode": "Uploading @name... Due to browser's limitation, calculate attachment information may cause some lag...",
|
||||
"realm": "Realm",
|
||||
"realms": "Realms",
|
||||
"realmOrganizing": "Organize a realm",
|
||||
"realmAlias": "Alias (Identifier)",
|
||||
"realmName": "Name",
|
||||
"realmDescription": "Description",
|
||||
"realmPublic": "Public Realm",
|
||||
"realmCommunity": "Community Realm",
|
||||
"realmAvatar": "Realm avatar",
|
||||
"realmBanner": "Realm banner",
|
||||
"realmDetail": "Realm detail",
|
||||
"realmMember": "Realm member",
|
||||
"realmMembers": "Realm members",
|
||||
"realmMembersAdd": "Add realm members",
|
||||
"realmMembersAddHint": "Into @realm",
|
||||
"realmAdjust": "Realm adjustment",
|
||||
"realmSettings": "Realm settings",
|
||||
"realmEditingNotify": "You're editing realm @realm",
|
||||
"realmLeaveConfirm": "Confirm realm quit",
|
||||
"realmLeaveConfirmCaption": "Are you sure you want leave realm @realm? Your content published in this realm will not be deleted.",
|
||||
"realmDeletionConfirm": "Confirm realm deletion",
|
||||
"realmDeletionConfirmCaption": "Are you sure to delete realm @realm? This action cannot be undone!",
|
||||
"channels": "Channels",
|
||||
"channelNew": "Create a new channel",
|
||||
"channelNewInRealmHint": "Create channel in realm @realm",
|
||||
"channelOrganizing": "Organize a channel",
|
||||
"channelOrganizeCommon": "Create regular channel",
|
||||
"channelOrganizeDirect": "Create DM",
|
||||
"channelOrganizeDirectHint": "Choose friend to create DM",
|
||||
"channelInRealmNotify": "You're creating channel in realm @realm",
|
||||
"channelEditingNotify": "You're editing channel @channel",
|
||||
"channelAlias": "Alias (Identifier)",
|
||||
"channelName": "Name",
|
||||
"channelDescription": "Description",
|
||||
"channelDirectDescription": "Direct message with @username",
|
||||
"channelPublic": "Public channel",
|
||||
"channelCommunity": "Community channel",
|
||||
"channelMember": "Channel member",
|
||||
"channelMembers": "Channel members",
|
||||
"channelMembersAdd": "Add channel members",
|
||||
"channelMembersAddHint": "Into @channel",
|
||||
"channelType": "Channel type",
|
||||
"channelTypeCommon": "Regular",
|
||||
"channelTypeDirect": "DM",
|
||||
"channelAdjust": "Channel adjustment",
|
||||
"channelDetail": "Channel detail",
|
||||
"channelSettings": "Channel settings",
|
||||
"channelLeaveConfirm": "Confirm channel quit",
|
||||
"channelLeaveConfirmCaption": "Are you sure to leave channel @channel? All your messages will be deleted!",
|
||||
"channelDeletionConfirm": "Confirm channel deletion",
|
||||
"channelDeletionConfirmCaption": "Are you sure to delete channel @channel? This action cannot be undone!",
|
||||
"channelCategoryDirect": "DM",
|
||||
"channelCategoryDirectHint": "Your direct messages",
|
||||
"channelNotifyLevel": "Notify level",
|
||||
"channelNotifyLevelAll": "All",
|
||||
"channelNotifyLevelMentioned": "Only mentioned",
|
||||
"channelNotifyLevelNone": "Ignore all",
|
||||
"channelNotifyLevelApplied": "Your notification settings has been applied.",
|
||||
"messageUnSync": "Messages Un-synced",
|
||||
"messageUnSyncCaption": "@count message(s) still in un-synced.",
|
||||
"messageSending": "Sending...",
|
||||
"messageEditDesc": "Edited message @id",
|
||||
"messageDeleteDesc": "Deleted message @id",
|
||||
"messageCallStartDesc": "@user starts a call",
|
||||
"messageCallEndDesc": "Call last for @duration",
|
||||
"messageTypeUnsupported": "Unsupported Message: @type",
|
||||
"messageInputPlaceholder": "Message @channel",
|
||||
"messageActionList": "Actions of Message",
|
||||
"messageDeletionConfirm": "Confirm message deletion",
|
||||
"messageDeletionConfirmCaption": "Are your sure to delete message @id? This action cannot be undone!",
|
||||
"call": "Call",
|
||||
"callOngoing": "A call is ongoing...",
|
||||
"callOngoingEmpty": "A call is on hold...",
|
||||
"callOngoingParticipants": "@count people are calling...",
|
||||
"callOngoingJoined": "Call last @duration",
|
||||
"callJoin": "Join",
|
||||
"callResume": "Resume",
|
||||
"callMicrophone": "Microphone",
|
||||
"callMicrophoneDisabled": "Microphone Disabled",
|
||||
"callMicrophoneSelect": "Select Microphone",
|
||||
"callCamera": "Camera",
|
||||
"callCameraDisabled": "Camera Disabled",
|
||||
"callCameraSelect": "Select Camera",
|
||||
"callSpeakerSelect": "Select Speaker",
|
||||
"callDisconnected": "Call Disconnected... @reason",
|
||||
"callMicrophoneOn": "Turn Microphone On",
|
||||
"callMicrophoneOff": "Turn Microphone Off",
|
||||
"callCameraOn": "Turn Camera On",
|
||||
"callCameraOff": "Turn Camera Off",
|
||||
"callVideoFlip": "Flip Video Input",
|
||||
"callSpeakerphoneToggle": "Toggle Speakerphone Mode",
|
||||
"callScreenOn": "Start Screen Sharing",
|
||||
"callScreenOff": "Stop Screen Sharing",
|
||||
"callDisconnect": "Disconnect",
|
||||
"callDisconnectCaption": "Are you sure you want to disconnect from this call? You can also just return to the page, and the call will continue in the background.",
|
||||
"callParticipantAction": "Participant Actions",
|
||||
"callParticipantMicrophoneOff": "Mute Participant",
|
||||
"callParticipantMicrophoneOn": "Unmute Participant",
|
||||
"callParticipantVideoOff": "Turn Off Participant Video",
|
||||
"callParticipantVideoOn": "Turn On Participant Video",
|
||||
"callAlreadyOngoing": "A call is already ongoing",
|
||||
"badge": "Badge",
|
||||
"badges": "Badges",
|
||||
"badgeGrantAt": "Badge awarded on @date",
|
||||
"badgeSolsynthStaff": "Solsynth Staff",
|
||||
"badgeSolarOriginalCitizen": "Solar Network Natives",
|
||||
"badgeGreatCommunityContributor": "Great Community Contributor",
|
||||
"pushNotifyRegister": "Register Push Notification Device",
|
||||
"pushNotifyRegisterCaption": "Activating push notifications allows you to get our latest notifications even when the app is completely closed. We use Apple's official push service on iOS/macOS devices; other devices provide push notifications through Google Firebase. To register a device for push notifications, you may need to connect to Google's servers and install the Google Framework on your device. Although you dismiss this dialog, this registration will be auto performed when you next time launch the app.",
|
||||
"pushNotifyRegisterDone": "Push notifications has been activated.",
|
||||
"pushNotifyRegisterFailed": "Unable to active push notification... @reason",
|
||||
"accountChangeStatus": "Change Status",
|
||||
"accountCustomStatus": "Set Custom Status",
|
||||
"accountClearStatus": "Clear Status",
|
||||
"accountStatusOnline": "Online",
|
||||
"accountStatusSilent": "Do not Disturb",
|
||||
"accountStatusSilentDesc": "The notification will stop popping up",
|
||||
"accountStatusInvisible": "Invisible",
|
||||
"accountStatusInvisibleDesc": "Will show as offline, but all features still remain normal",
|
||||
"accountStatusOffline": "Offline",
|
||||
"accountLastSeenAt": "@date ago online",
|
||||
"accountStatusLabel": "Status Text",
|
||||
"accountStatusClearAt": "Clear At",
|
||||
"accountStatusNegative": "Negative",
|
||||
"accountStatusNeutral": "Neutral",
|
||||
"accountStatusPositive": "Positive",
|
||||
"bsLoadingTheme": "Loading Theme",
|
||||
"bsCheckForUpdate": "Checking For Updates",
|
||||
"bsCheckForUpdateFailed": "Unable to Check Updates",
|
||||
"bsCheckForUpdateNew": "Found New Version",
|
||||
"bsCheckForUpdateDesc": "Please head to app store and update your app to latest version to prevent error happens and get latest functions.",
|
||||
"bsCheckingServer": "Checking Server Status",
|
||||
"bsCheckingServerFail": "Unable connect to server, check your network connection",
|
||||
"bsCheckingServerDown": "Server currently unavailable, please retry later",
|
||||
"bsAuthorizing": "Authorizing",
|
||||
"bsEstablishingConn": "Establishing Connection",
|
||||
"bsPreparingData": "Preparing User Data",
|
||||
"bsRegisteringPushNotify": "Enabling Push Notifications",
|
||||
"bsDismissibleErrorHint": "Click anywhere to ignore this error",
|
||||
"bsContinuable": "Click anywhere to continue",
|
||||
"postShareContent": "@content\n\n@username on the Solar Network\nCheck it out: @link",
|
||||
"postShareSubject": "@title by @username on Solar Network",
|
||||
"themeColor": "Global Theme Color",
|
||||
"themeColorRed": "Modern Red",
|
||||
"themeColorBlue": "Classic Blue",
|
||||
"themeColorMiku": "Miku Blue",
|
||||
"themeColorKagamine": "Kagamine Yellow",
|
||||
"themeColorLuka": "Luka Pink",
|
||||
"stickerDeletionConfirm": "Confirm sticker delete",
|
||||
"stickerDeletionConfirmCaption": "Are you sure to delete sticker @name? This action cannot be undo.",
|
||||
"themeColorApplied": "Global theme color has been applied.",
|
||||
"attachmentSaved": "Attachment saved to your system album.",
|
||||
"cropImage": "Crop Image",
|
||||
"stickerUploader": "Upload sticker",
|
||||
"stickerUploaderAttachmentNew": "Upload sticker",
|
||||
"stickerUploaderAttachment": "Attachment serial number",
|
||||
"stickerUploaderPack": "Sticker pack serial number",
|
||||
"stickerUploaderPackHint": "Don't have pack id? Head to creator platform and create one!",
|
||||
"stickerUploaderAlias": "Alias",
|
||||
"stickerUploaderAliasHint": "Will be used as a placeholder with the sticker pack prefix when entered.",
|
||||
"stickerUploaderName": "Name",
|
||||
"stickerUploaderNameHint": "A human-friendly name given to the user in the sticker selection interface.",
|
||||
"readMore": "Read more",
|
||||
"attachmentUnload": "Not Loaded",
|
||||
"attachmentUnloadCaption": "In order to save traffic, this attachment is not loaded automatically. Click it to start loading.",
|
||||
"callStatusConnected": "Connected",
|
||||
"callStatusDisconnected": "Disconnected",
|
||||
"callStatusConnecting": "Connecting",
|
||||
"callStatusReconnected": "Reconnecting",
|
||||
"messageOutOfSync": "May Out of Sync with Server",
|
||||
"messageOutOfSyncCaption": "Since the App has entered the background, there may be a time difference between the message list and the server. Click to Refresh.",
|
||||
"localDatabaseWipe": "Wipe local database",
|
||||
"localDatabaseSize": "Overall database size: @size",
|
||||
"unknown": "Unknown",
|
||||
"collapse": "Collapse",
|
||||
"expand": "Expand",
|
||||
"typingMessage": "@user are typing...",
|
||||
"userLevel0": "Newbie",
|
||||
"userLevel1": "Novice",
|
||||
"userLevel2": "Apprentice",
|
||||
"userLevel3": "Explorer",
|
||||
"userLevel4": "Adventurer",
|
||||
"userLevel5": "Warrior",
|
||||
"userLevel6": "Knight",
|
||||
"userLevel7": "Champion",
|
||||
"userLevel8": "Hero",
|
||||
"userLevel9": "Master",
|
||||
"userLevel10": "Grandmaster",
|
||||
"userLevel11": "Legend",
|
||||
"userLevel12": "Mythic",
|
||||
"userLevel13": "Immortal",
|
||||
"postBrowsingIn": "Browsing in @region",
|
||||
"needRestartToApply": "Restart the application to take effect",
|
||||
"holdToSeeDetail": "Long press / Mouse hover to see detail",
|
||||
"subscribe": "Subscribe",
|
||||
"subscribed": "Subscribed",
|
||||
"unsubscribe": "Unsubscribe",
|
||||
"preferences": "Preferences",
|
||||
"notificationPreferences": "Notification preferences",
|
||||
"notificationTopicPostFeedback": "Post feedbacks",
|
||||
"notificationTopicPostSubscription": "Post subscriptions",
|
||||
"preferencesApplied": "Preferences has been applied.",
|
||||
"save": "Save",
|
||||
"updateAvailable": "Update available",
|
||||
"updateAvailableDesc": "There is an update available (@from to @to). Do you want to download and install it now? You can still use the app normally while waiting for the download to complete.",
|
||||
"update": "Update",
|
||||
"updateCheckStrictly": "Strict mode",
|
||||
"updateCheckStrictlyDesc": "If enabled, the app will ask for updating once the local version is different from remote one.",
|
||||
"updateMayAvailable": "App version @version is available, you can update from app store or our website.",
|
||||
"updateNow": "Update now",
|
||||
"termAccept": "I've read and agree to Solar Network's Terms",
|
||||
"termAcceptDesc": "Including but not limited to \"User Agreement\" and \"Privacy Policy\"",
|
||||
"termAcceptLink": "View terms",
|
||||
"termAcceptNextWithAgree": "By clicking the \"Next\", it means you agree to our terms and its updates. You should already agreed with them while you sign up.",
|
||||
"termRelated": "Related Terms",
|
||||
"appDetails": "App Details",
|
||||
"projectWebsite": "Project Website",
|
||||
"iAmNotRobot": "I'm not a Robot",
|
||||
"report": "Report",
|
||||
"reportAbuse": "Report abuse",
|
||||
"reportAbuseDesc": "Report any violation of service terms",
|
||||
"reportAbuseResource": "Resource identifier",
|
||||
"reportAbuseReason": "Report reason",
|
||||
"reportSubmitted": "Report submitted, thank you for your contribution. We will send a notification about the result of the report within 24 hours for you.",
|
||||
"accountDeletion": "Request account deletion",
|
||||
"accountDeletionDesc": "Delete the current account and all its data. Note that this action is irreversible!",
|
||||
"accountDeletionConfirm": "Confirm request account deletion",
|
||||
"accountDeletionConfirmDesc": "Are you sure to delete account @account? You will receive a confirmation email with a link to confirm the deletion of the account within 24 hours. Note that this action is irreversible, and all data associated with the account will be deleted, and you should be careful about it.",
|
||||
"accountDeletionRequested": "Account deletion requested, check your inbox to confirm the request.",
|
||||
"slideToConfirm": "Slide to confirm",
|
||||
"serviceStatus": "Status of Service",
|
||||
"firstBootTime": "First boot at @time",
|
||||
"rateTheApp": "Rate the app",
|
||||
"rateTheAppDesc": "Rate Solar Network on the App Store to let us serve you better!",
|
||||
"friendAdd": "Add as friend",
|
||||
"blockUser": "Block user",
|
||||
"unblockUser": "Unblock user",
|
||||
"learnMoreAboutPerson": "Learn more about that person",
|
||||
"global": "Global",
|
||||
"all": "All",
|
||||
"unablePreview": "Unable to preview",
|
||||
"dashboardNav": "Dash",
|
||||
"accountNav": "You",
|
||||
"performance": "Performance",
|
||||
"animatedMessageList": "Non-animated message list",
|
||||
"animatedMessageListDesc": "Remove animation effects in message list, to reduce cause lag",
|
||||
"theme": "Theme",
|
||||
"globalTheme": "Global theme",
|
||||
"agedTheme": "Old school style theme",
|
||||
"agedThemeDesc": "Downgrade the global theme to Material Design 2. Unexpected issues may occur. For experimental use only.",
|
||||
"appBackgroundImage": "Global background image",
|
||||
"appBackgroundImageDesc": "The global background image will be displayed on all pages",
|
||||
"authPreferences": "Auth preferences",
|
||||
"authPreferencesDesc": "Set the security behavior of your account",
|
||||
"authMaximumAuthSteps": "Maximum authentication steps",
|
||||
"authMaximumAuthStepsDesc": "The maximum number of authentication steps when logging in, higher value is more secure, lower value is more convenient; default is 2",
|
||||
"auditLog": "Audit log",
|
||||
"shareImage": "Share as image",
|
||||
"shareImageFooter": "Only on the Solar Network",
|
||||
"fileSavedAt": "File saved at @path",
|
||||
"showIp": "Show IP Address",
|
||||
"shotOn": "Shot on @device",
|
||||
"unread": "Unread",
|
||||
"searchTook": "Took @time",
|
||||
"searchResult": "@count Matches",
|
||||
"happyBirthday": "Happy birthday @name!",
|
||||
"happyBirthdayDesc": "Today is your @count birthday"
|
||||
}
|
494
assets/locales/zh_cn.json
Normal file
@ -0,0 +1,494 @@
|
||||
{
|
||||
"done": "完成",
|
||||
"hide": "隐藏",
|
||||
"okay": "确认",
|
||||
"home": "首页",
|
||||
"next": "下一步",
|
||||
"prev": "上一步",
|
||||
"reset": "重置",
|
||||
"cancel": "取消",
|
||||
"confirm": "确认",
|
||||
"leave": "离开",
|
||||
"loading": "载入中…",
|
||||
"guest": "游客",
|
||||
"about": "关于",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"insert": "插入",
|
||||
"settings": "设置",
|
||||
"settingsNotificationBgService": "常驻通知服务",
|
||||
"settingsNotificationBgServiceDesc": "在设备常驻一个通知服务,使得部分不支持推送通知的设备可以在后台收到通知;启用该功能的情况下不会向服务器注册推送通知,并且你会始终在他人眼中成为在线(隐身除外);可能需要在设置中关闭电量与流量优化。",
|
||||
"page": "页面",
|
||||
"draft": "草稿",
|
||||
"draftSave": "存为草稿",
|
||||
"draftBox": "草稿箱",
|
||||
"more": "更多",
|
||||
"share": "分享",
|
||||
"shareNoUri": "分享文字内容",
|
||||
"alias": "别名",
|
||||
"feed": "资讯",
|
||||
"explore": "探索",
|
||||
"posts": "帖子",
|
||||
"unlink": "移除链接",
|
||||
"dashboard": "仪表盘",
|
||||
"today": "今日",
|
||||
"yesterday": "昨日",
|
||||
"postSearch": "搜索帖子",
|
||||
"postSearchWithTag": "检索带有 #@key 标签的资讯",
|
||||
"postSearchWithCategory": "检索位于分类 @category 的资讯",
|
||||
"feedUnreadCount": "@count 条你可能错过的帖子",
|
||||
"messages": "消息",
|
||||
"messagesUnreadCount": "@count 条未读的消息",
|
||||
"dailySign": "签到",
|
||||
"dailySignAction": "烧香拜佛",
|
||||
"dailySignHistoryAction": "查看运势历史",
|
||||
"dailySignNone": "今日未拜访佛祖",
|
||||
"dailySignTier0": "诸事不宜",
|
||||
"dailySignTier1": "有些不宜",
|
||||
"dailySignTier2": "平平淡淡",
|
||||
"dailySignTier3": "有些事宜",
|
||||
"dailySignTier4": "诸事皆宜",
|
||||
"dailySignHistoryTitle": "运势历史",
|
||||
"dailySignHistoryRecent": "近期运势",
|
||||
"dailySignHistoryReward": "成果趋势",
|
||||
"dashboardFooter": "占卜多少沾点玩,人生还得靠实力",
|
||||
"visitProfilePage": "造访个人主页",
|
||||
"profilePage": "主页",
|
||||
"profilePosts": "帖子",
|
||||
"profileAlbum": "相簿",
|
||||
"chat": "聊天",
|
||||
"apply": "应用",
|
||||
"search": "搜索",
|
||||
"post": "帖子",
|
||||
"article": "文章",
|
||||
"reply": "回复",
|
||||
"repost": "转帖",
|
||||
"openInAlbum": "在相簿中打开",
|
||||
"openInBrowser": "在浏览器中打开",
|
||||
"notification": "通知",
|
||||
"notificationUnreadCount": "@count 条未读通知",
|
||||
"errorHappened": "发生错误了",
|
||||
"errorHappenedUnauthorized": "未经授权的请求,请登录或尝试重新登录。",
|
||||
"errorHappenedRequestBad": "请求错误,服务器拒绝处理该请求,请检查您的请求数据。",
|
||||
"errorHappenedRequestForbidden": "请求错误,权限不足。",
|
||||
"errorHappenedRequestNotFound": "请求错误,请求的数据不存在。",
|
||||
"errorHappenedRequestConnection": "网络请求失败,请检查连接状态与服务状态后再试。",
|
||||
"errorHappenedRequestUnknown": "请求错误,类型未知,请将本提示完整截图提交反馈。",
|
||||
"forgotPassword": "忘记密码",
|
||||
"email": "邮件地址",
|
||||
"username": "用户名",
|
||||
"usernameInputHint": "同时支持邮箱 / 电话号码",
|
||||
"nickname": "显示名",
|
||||
"password": "密码",
|
||||
"passwordOneTime": "一次性验证码",
|
||||
"passwordInputHint": "忘记密码了?回到第一步以重置密码",
|
||||
"passwordOneTimeInputHint": "检查你的收件箱或是授权器获得以验证码",
|
||||
"title": "标题",
|
||||
"description": "简介",
|
||||
"birthday": "生日",
|
||||
"firstName": "名称",
|
||||
"lastName": "姓氏",
|
||||
"account": "账号",
|
||||
"accountProfile": "个人资料",
|
||||
"accountProfileApplied": "账户的资料已保存。",
|
||||
"accountStickers": "贴图",
|
||||
"accountFriend": "好友",
|
||||
"accountFriendNew": "添加好友",
|
||||
"accountFriendNewHint": "使用他人的用户名来发送一个好友请求吧!",
|
||||
"accountFriendPending": "好友请求",
|
||||
"accountFriendBlocked": "好友黑名单",
|
||||
"accountFriendListHint": "左滑来拒绝,右滑来接受",
|
||||
"accountFriendRequestSent": "好友请求已发送,等待处理对方中……",
|
||||
"accountBlocked": "已屏蔽账号",
|
||||
"accountUnblocked": "已解除屏蔽账号",
|
||||
"accountSuspended": "帐号被停用",
|
||||
"accountSuspendedAt": "该帐号自 @date 起被停用",
|
||||
"aspectRatio": "纵横比",
|
||||
"aspectRatioSquare": "方型",
|
||||
"aspectRatioPortrait": "竖型",
|
||||
"aspectRatioLandscape": "横型",
|
||||
"unsignedIn": "未登录",
|
||||
"signin": "登录",
|
||||
"signinRequired": "需要登录",
|
||||
"signinRequiredHint": "登陆以获得 Solar Network 的全部功能使用权。",
|
||||
"signinGreeting": "欢迎回来\nSolar Network",
|
||||
"signinCaption": "登录以发表帖子、文章、创建领域、和你的朋友聊天,以及获取更多功能!",
|
||||
"signinRiskDetected": "检测到风险,点击下一步按钮来打开一个网页,并通过在其上面登录来通过安全检查。",
|
||||
"signinResetPasswordHint": "请先填写用户名以发送重置密码请求。",
|
||||
"signinResetPasswordSent": "重置密码请求已发送,在绑定邮件收件箱可收取一份包含重置密码链接的邮件。",
|
||||
"signinPickFactor": "选择一个\n验证方式",
|
||||
"signinEnterPassword": "输入密码\n或验证码",
|
||||
"signinMultiFactor": "@n 步验证",
|
||||
"authFactorEmail": "邮箱一次性密码",
|
||||
"authFactorPassword": "账户密码",
|
||||
"signup": "注册",
|
||||
"signupGreeting": "欢迎加入\nSolar Network",
|
||||
"signupCaption": "在 Solarpass 注册一个账号以获得整个 Solar Network 的存取权!",
|
||||
"signupDone": "注册成功",
|
||||
"signupDoneCaption": "你成功地注册了一个帐户,现在去尝试登陆吧!",
|
||||
"signout": "登出",
|
||||
"joinedAt": "加入于 @date",
|
||||
"riskDetection": "检测到风险",
|
||||
"matureContent": "评级内容",
|
||||
"matureContentCaption": "该内容已被评级为家长指导级或以上,这可能说明内容包含一系列不友好的成分",
|
||||
"notifyAllRead": "已读所有通知",
|
||||
"notifyEmpty": "通知箱为空",
|
||||
"notifyEmptyCaption": "看起来最近没发生什么呢",
|
||||
"totalSocialCreditPoints": "社会信用点",
|
||||
"totalPostCount": "总帖数",
|
||||
"totalUpvote": "获顶数",
|
||||
"totalDownvote": "获踩数",
|
||||
"clear": "清除",
|
||||
"pinPost": "置顶本帖",
|
||||
"unpinPost": "取消置顶本帖",
|
||||
"postRestoreFromLocal": "内容从本地暂存回复",
|
||||
"postAutoSaveAt": "已自动保存于 @date",
|
||||
"postCategoriesAndTags": "分类与标签",
|
||||
"postPublishDate": "发布时间",
|
||||
"postPublishAt": "发布帖子于",
|
||||
"postPublishedUntil": "取消发布于",
|
||||
"postPublishZone": "帖子发布区",
|
||||
"postPublishZoneNone": "无所属领域",
|
||||
"postVisibility": "帖子可见性",
|
||||
"postVisibilityAll": "所有人可见",
|
||||
"postVisibilityFriends": "仅好友可见",
|
||||
"postVisibilitySelected": "选中者可见",
|
||||
"postVisibilityFiltered": "选中者不可见",
|
||||
"postVisibilityNone": "仅自己可见",
|
||||
"postVisibleUsers": "可见帖子者",
|
||||
"postInvisibleUsers": "隐藏帖子者",
|
||||
"postOverview": "帖子概览",
|
||||
"postThumbnail": "帖子缩略图",
|
||||
"postThumbnailAttachmentNew": "上传附件作为缩略图",
|
||||
"postThumbnailAttachment": "附件序列号",
|
||||
"postPinned": "已置顶",
|
||||
"postEditorModeStory": "发个帖子",
|
||||
"postEditorModeArticle": "撰写文章",
|
||||
"postEditor": "帖子编辑器",
|
||||
"articleEditor": "撰写文章",
|
||||
"articleDetail": "文章详情",
|
||||
"draftBoxOpen": "打开草稿箱",
|
||||
"postListNews": "新鲜事",
|
||||
"postListFriends": "好友圈",
|
||||
"postListShuffle": "打乱看",
|
||||
"attachmentThumbnail": "附件缩略图",
|
||||
"attachmentThumbnailAttachmentNew": "上传附件作为缩略图",
|
||||
"attachmentThumbnailAttachment": "附件序列号",
|
||||
"postNew": "创建新帖子",
|
||||
"postNewInRealmHint": "在领域 @realm 里发表新帖子",
|
||||
"postAction": "发表",
|
||||
"postEdited": "编辑于 @date",
|
||||
"postNewCreated": "创建于 @date",
|
||||
"postInRealm": "发表于 @realm",
|
||||
"attachmentHint": "@count 个附件",
|
||||
"postDetail": "帖子详情",
|
||||
"postReplies": "帖子回复",
|
||||
"postPublish": "编辑帖子",
|
||||
"postIdentityNotify": "你将会以本身份发表帖子",
|
||||
"postContentPlaceholder": "发生什么事了?!",
|
||||
"postTagsPlaceholder": "标签",
|
||||
"postReaction": "帖子的反应",
|
||||
"postActionList": "帖子的操作",
|
||||
"postReplyAction": "发表一则回复",
|
||||
"postRepliedNotify": "回了一个 @username 的帖子",
|
||||
"postRepostedNotify": "转了一个 @username 的帖子",
|
||||
"postInRealmNotify": "你正在领域 @realm 中发表帖子",
|
||||
"postEditingNotify": "你正在编辑一个你发布的帖子",
|
||||
"postReplyingNotify": "你正在回一个来自 @username 的帖子",
|
||||
"postRepostingNotify": "你正在转一个来自 @username 的帖子",
|
||||
"postDeletionConfirm": "确认删除帖子",
|
||||
"postDeletionConfirmCaption": "你确定要删除帖子 “@content” 吗?该操作不可撤销。",
|
||||
"reactAdd": "作出反应",
|
||||
"reactCompleted": "你的反应已被添加",
|
||||
"reactUncompleted": "你的反应已被移除",
|
||||
"attachmentUploadBy": "由上传",
|
||||
"attachmentAutoUpload": "自动上传",
|
||||
"attachmentUploadQueue": "上传队列",
|
||||
"attachmentUploadQueueStart": "整队上传",
|
||||
"attachmentUploadInProgress": "有附件正在上传,请等待所有附件上传完毕后再进行操作……",
|
||||
"attachmentAttached": "已附附件",
|
||||
"attachmentUploadBlocked": "上传受阻,当前已有任务进行中……",
|
||||
"attachmentAdd": "附加附件",
|
||||
"attachmentAddGalleryPhoto": "相册照片",
|
||||
"attachmentAddGalleryVideo": "相册视频",
|
||||
"attachmentAddCameraPhoto": "拍摄图片",
|
||||
"attachmentAddCameraVideo": "拍摄视频",
|
||||
"attachmentAddClipboard": "粘贴文件",
|
||||
"attachmentAddFile": "附加文件",
|
||||
"attachmentAddLink": "链接附件",
|
||||
"attachmentAddLinkHint": "输入附件的神秘代号来链接对应附件",
|
||||
"attachmentAddLinkInput": "神秘代号",
|
||||
"attachmentSetting": "调整附件",
|
||||
"attachmentAlt": "替代文字",
|
||||
"attachmentLoadFailed": "加载失败",
|
||||
"attachmentLoadFailedCaption": "有错误发生于加载附件元数据的过程中了…",
|
||||
"attachmentUploading": "上传附件 @name 中…",
|
||||
"attachmentUploadingWebMode": "上传附件 @name 中… 由于浏览器单线程限制,计算所需资源可能会导致界面卡顿…",
|
||||
"realm": "领域",
|
||||
"realms": "领域",
|
||||
"realmOrganizing": "组织领域",
|
||||
"realmAlias": "别称(标识符)",
|
||||
"realmName": "显示名称",
|
||||
"realmDescription": "领域简介",
|
||||
"realmPublic": "公开领域",
|
||||
"realmCommunity": "社区领域",
|
||||
"realmAvatar": "领域头像",
|
||||
"realmBanner": "领域横幅",
|
||||
"realmDetail": "领域详情",
|
||||
"realmMember": "领域成员",
|
||||
"realmMembers": "领域成员",
|
||||
"realmMembersAdd": "添加领域成员",
|
||||
"realmMembersAddHint": "到 @realm",
|
||||
"realmAdjust": "调整领域",
|
||||
"realmSettings": "领域设置",
|
||||
"realmEditingNotify": "你正在编辑领域 @realm",
|
||||
"realmLeaveConfirm": "确认离开领域",
|
||||
"realmLeaveConfirmCaption": "你确认要离开领域 @realm 吗?你在该领域发表的内容不会被删除。",
|
||||
"realmDeletionConfirm": "确认删除领域",
|
||||
"realmDeletionConfirmCaption": "你确定要删除领域 @realm 嘛?该操作不可撤销。",
|
||||
"channels": "频道",
|
||||
"channelNew": "创建新频道",
|
||||
"channelNewInRealmHint": "在领域 @realm 里创建新频道",
|
||||
"channelOrganizing": "组织频道",
|
||||
"channelOrganizeCommon": "创建普通频道",
|
||||
"channelOrganizeDirect": "创建私信频道",
|
||||
"channelOrganizeDirectHint": "选择好友来创建私信",
|
||||
"channelInRealmNotify": "你正在领域 @realm 中创建频道",
|
||||
"channelEditingNotify": "你正在编辑频道 @channel",
|
||||
"channelAlias": "别称(标识符)",
|
||||
"channelName": "显示名称",
|
||||
"channelDescription": "频道简介",
|
||||
"channelDirectDescription": "与 @username 的私聊",
|
||||
"channelPublic": "公开频道",
|
||||
"channelCommunity": "社区频道",
|
||||
"channelMember": "频道成员",
|
||||
"channelMembers": "频道成员",
|
||||
"channelMembersAdd": "添加频道成员",
|
||||
"channelMembersAddHint": "到 @channel",
|
||||
"channelType": "频道类型",
|
||||
"channelTypeCommon": "普通频道",
|
||||
"channelTypeDirect": "私信",
|
||||
"channelAdjust": "调整频道",
|
||||
"channelDetail": "频道详情",
|
||||
"channelSettings": "频道设置",
|
||||
"channelLeaveConfirm": "确认离开频道",
|
||||
"channelLeaveConfirmCaption": "你确认要离开频道 @channel 吗?你在这个频道的消息将被删除。",
|
||||
"channelDeletionConfirm": "确认删除频道",
|
||||
"channelDeletionConfirmCaption": "你确认要删除频道 @channel 吗?该操作不可撤销。",
|
||||
"channelCategoryDirect": "私聊频道",
|
||||
"channelCategoryDirectHint": "你的所有私聊频道",
|
||||
"channelNotifyLevel": "通知等级",
|
||||
"channelNotifyLevelAll": "全部通知",
|
||||
"channelNotifyLevelMentioned": "仅提及",
|
||||
"channelNotifyLevelNone": "忽略一切",
|
||||
"channelNotifyLevelApplied": "你的通知设置已经应用。",
|
||||
"messageUnSync": "消息未同步",
|
||||
"messageUnSyncCaption": "还有 @count 条消息未同步",
|
||||
"messageSending": "消息发送中…",
|
||||
"messageEditDesc": "修改了消息 @id",
|
||||
"messageDeleteDesc": "删除了消息 @id",
|
||||
"messageCallStartDesc": "@user 发起了一次通话",
|
||||
"messageCallEndDesc": "通话持续了 @duration",
|
||||
"messageTypeUnsupported": "不支持的消息类型 @type",
|
||||
"messageInputPlaceholder": "发消息于 @channel",
|
||||
"messageActionList": "消息的操作",
|
||||
"messageDeletionConfirm": "确认删除消息",
|
||||
"messageDeletionConfirmCaption": "你确定要删除消息 @id 吗?该操作不可撤销。",
|
||||
"call": "通话",
|
||||
"callOngoing": "一则通话正在进行中…",
|
||||
"callOngoingEmpty": "一则通话待机中…",
|
||||
"callOngoingParticipants": "@count 人正在进行通话…",
|
||||
"callOngoingJoined": "通话进行 @duration",
|
||||
"callJoin": "加入",
|
||||
"callResume": "恢复",
|
||||
"callMicrophone": "麦克风",
|
||||
"callMicrophoneDisabled": "麦克风禁用",
|
||||
"callMicrophoneSelect": "选择麦克风",
|
||||
"callCamera": "摄像头",
|
||||
"callCameraDisabled": "摄像头禁用",
|
||||
"callCameraSelect": "选择摄像头",
|
||||
"callSpeakerSelect": "选择扬声器",
|
||||
"callDisconnected": "通话已断开… @reason",
|
||||
"callMicrophoneOn": "开启麦克风",
|
||||
"callMicrophoneOff": "关闭麦克风",
|
||||
"callCameraOn": "开启摄像头",
|
||||
"callCameraOff": "关闭摄像头",
|
||||
"callVideoFlip": "翻转视频输入",
|
||||
"callSpeakerphoneToggle": "切换扬声器模式",
|
||||
"callScreenOn": "启动屏幕分享",
|
||||
"callScreenOff": "关闭屏幕分享",
|
||||
"callDisconnect": "断开连接",
|
||||
"callDisconnectCaption": "你确定要断开与该则通话的连接吗?你也可以直接返回页面,通话将在后台继续。",
|
||||
"callParticipantAction": "通话参与者的操作",
|
||||
"callParticipantMicrophoneOff": "静音参与者",
|
||||
"callParticipantMicrophoneOn": "解除静音参与者",
|
||||
"callParticipantVideoOff": "静音参与者",
|
||||
"callParticipantVideoOn": "解除静音参与者",
|
||||
"callAlreadyOngoing": "当前正在进行一则通话",
|
||||
"badge": "徽章",
|
||||
"badges": "徽章",
|
||||
"badgeGrantAt": "徽章颁发于 @date",
|
||||
"badgeSolsynthStaff": "Solsynth 工作人员",
|
||||
"badgeSolarOriginalCitizen": "Solar Network 原住民",
|
||||
"badgeGreatCommunityContributor": "优秀社区贡献者",
|
||||
"pushNotifyRegister": "注册推送通知设备",
|
||||
"pushNotifyRegisterCaption": "激活推送通知便可以让你在应用程序完全关闭的时候仍然获取到我们最新的通知。在 iOS/macOS 设备上我们使用 Apple 官方的推送服务;其他设备则通过 Google Firebase 提供推送通知。要注册推送通知设备,您可能需要连接到 Google 的服务器(在中国大陆不可用)并在您的设备上安装 Google Framework。即使您关闭此对话框,下次启动应用程序时仍会自动执行此注册。",
|
||||
"pushNotifyRegisterDone": "推送通知已成功激活",
|
||||
"pushNotifyRegisterFailed": "推送通知激活失败…… @reason",
|
||||
"accountChangeStatus": "变更状态",
|
||||
"accountCustomStatus": "自定义状态",
|
||||
"accountClearStatus": "清除状态",
|
||||
"accountStatusOnline": "在线",
|
||||
"accountStatusSilent": "请勿打扰",
|
||||
"accountStatusSilentDesc": "将会暂停所有通知推送",
|
||||
"accountStatusInvisible": "隐身",
|
||||
"accountStatusInvisibleDesc": "将会在他人界面显示离线,但不影响功能使用",
|
||||
"accountStatusOffline": "离线",
|
||||
"accountLastSeenAt": "最后上线于 @date 前",
|
||||
"accountStatusLabel": "状态文字",
|
||||
"accountStatusClearAt": "清除状态于",
|
||||
"accountStatusNegative": "负面",
|
||||
"accountStatusNeutral": "中性",
|
||||
"accountStatusPositive": "积极",
|
||||
"bsLoadingTheme": "正在装载主题",
|
||||
"bsCheckForUpdate": "正在检查更新",
|
||||
"bsCheckForUpdateFailed": "无法检查更新",
|
||||
"bsCheckForUpdateNew": "发现新版本",
|
||||
"bsCheckForUpdateDesc": "请前往应用商店并将您的应用程序更新到最新版本,以防止出现错误并获取最新功能。",
|
||||
"bsCheckingServer": "检查服务器状态中",
|
||||
"bsCheckingServerFail": "无法连接至服务器,请检查你的网络连接状态",
|
||||
"bsCheckingServerDown": "当前服务器不可用,请稍后重试",
|
||||
"bsAuthorizing": "正在授权中",
|
||||
"bsEstablishingConn": "部署连接中",
|
||||
"bsPreparingData": "正在准备用户资料",
|
||||
"bsRegisteringPushNotify": "正在启用推送通知",
|
||||
"bsDismissibleErrorHint": "点击任意地方忽略此错误",
|
||||
"bsContinuable": "点击任意处继续",
|
||||
"postShareContent": "@content\n\n@username 在 Solar Network\n原帖地址:@link",
|
||||
"postShareSubject": "@username 在 Solar Network 发表的 @title",
|
||||
"themeColor": "全局主题色",
|
||||
"themeColorRed": "现代红",
|
||||
"themeColorBlue": "经典蓝",
|
||||
"themeColorMiku": "未来蓝",
|
||||
"themeColorKagamine": "镜音黄",
|
||||
"themeColorLuka": "流音粉",
|
||||
"themeColorApplied": "全局主题颜色已应用",
|
||||
"stickerDeletionConfirm": "确认删除贴图",
|
||||
"stickerDeletionConfirmCaption": "你确认要删除贴图 @name 吗?该操作不可撤销。",
|
||||
"attachmentSaved": "附件已保存到系统相册",
|
||||
"cropImage": "裁剪图片",
|
||||
"stickerUploader": "上传贴图",
|
||||
"stickerUploaderAttachmentNew": "上传附件作为贴图",
|
||||
"stickerUploaderAttachment": "附件序列号",
|
||||
"stickerUploaderPack": "贴图包序号",
|
||||
"stickerUploaderPackHint": "没有该序号?请转到我们的创作者平台创建一个贴图包。",
|
||||
"stickerUploaderAlias": "贴图别名",
|
||||
"stickerUploaderAliasHint": "将会在输入时使用和贴图包前缀组成占位符。",
|
||||
"stickerUploaderName": "贴图名称",
|
||||
"stickerUploaderNameHint": "在贴图选择界面提供给用户的人类友好名称。",
|
||||
"readMore": "阅读更多",
|
||||
"attachmentUnload": "附件未加载",
|
||||
"attachmentUnloadCaption": "为了节省流量,本附件未自动加载,点一下来开始加载。",
|
||||
"callStatusConnected": "已连接",
|
||||
"callStatusDisconnected": "已断开",
|
||||
"callStatusConnecting": "连接中",
|
||||
"callStatusReconnected": "重连中",
|
||||
"messageOutOfSync": "消息可能与服务器脱节",
|
||||
"messageOutOfSyncCaption": "由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。",
|
||||
"localDatabaseWipe": "清除本地数据库",
|
||||
"localDatabaseSize": "本地数据库大小:@size",
|
||||
"unknown": "未知",
|
||||
"collapse": "折叠",
|
||||
"expand": "展开",
|
||||
"typingMessage": "@user 正在输入中…",
|
||||
"userLevel0": "不慕名利",
|
||||
"userLevel1": "初出茅庐",
|
||||
"userLevel2": "小试牛刀",
|
||||
"userLevel3": "磨杵成针",
|
||||
"userLevel4": "披荆斩棘",
|
||||
"userLevel5": "力挽狂澜",
|
||||
"userLevel6": "一骑当千",
|
||||
"userLevel7": "所向披靡",
|
||||
"userLevel8": "气吞山河",
|
||||
"userLevel9": "登峰造极",
|
||||
"userLevel10": "出神入化",
|
||||
"userLevel11": "名垂千古",
|
||||
"userLevel12": "独占鳌头",
|
||||
"userLevel13": "万古流芳",
|
||||
"postBrowsingIn": "浏览 @region 内的帖子中",
|
||||
"needRestartToApply": "需要重启应用来生效",
|
||||
"holdToSeeDetail": "长按 / 鼠标悬浮来查看详情",
|
||||
"subscribe": "订阅",
|
||||
"subscribed": "已订阅",
|
||||
"unsubscribe": "取消订阅",
|
||||
"preferences": "偏好设置",
|
||||
"notificationPreferences": "通知偏好设置",
|
||||
"notificationTopicPostFeedback": "帖子反馈",
|
||||
"notificationTopicPostSubscription": "订阅源",
|
||||
"preferencesApplied": "偏好设置已应用",
|
||||
"save": "保存",
|
||||
"updateAvailable": "有可用更新",
|
||||
"updateAvailableDesc": "有可用更新 (@from 到 @to) 你想现在下载安装吗?在等待下载期间你仍可以正常使用。",
|
||||
"update": "更新",
|
||||
"updateCheckStrictly": "严格模式",
|
||||
"updateCheckStrictlyDesc": "如果启用,应用程序将会在本地版本与远程版本不同时询问更新,而不会检查版本号大小。",
|
||||
"updateNow": "立即更新",
|
||||
"updateMayAvailable": "版本 @version 现已可用,你可以前往应用商店或是我们的官网下载更新。",
|
||||
"termAccept": "我已阅读并同意 Solar Network 各项条款",
|
||||
"termAcceptDesc": "包括但不限于《用户守则》和《隐私政策》",
|
||||
"termAcceptLink": "浏览条款",
|
||||
"termAcceptNextWithAgree": "点击 “下一步”,即表示你同意我们的各项条款,包括其之后的更新。你应该在注册时已经同意过了。",
|
||||
"termRelated": "相关条款",
|
||||
"projectWebsite": "项目网站",
|
||||
"appDetails": "应用详情",
|
||||
"iAmNotRobot": "我不是机器人",
|
||||
"report": "举报",
|
||||
"reportAbuse": "举报滥用",
|
||||
"reportAbuseDesc": "举报任何违反服务条款的行为",
|
||||
"reportAbuseResource": "举报的资源",
|
||||
"reportAbuseReason": "举报的原因",
|
||||
"reportSubmitted": "举报已提交,感谢你的贡献。我们将通过通知在 24 小时内通知该举报的处理结果。",
|
||||
"accountDeletion": "请求删除账号",
|
||||
"accountDeletionDesc": "删除目前登陆的账号,及其所有的数据。注意,该操作不可撤销!",
|
||||
"accountDeletionConfirm": "确认账号删除请求",
|
||||
"accountDeletionConfirmDesc": "你确定要删除账号 @account 吗?你将会在其绑定的主要邮件地址收到一封包含着确认删除账号连接的邮件,在二十四小时内使用该连接即可完成删除账号。注意,本操作不可撤销,并且账号创建或关联的所有数据都将被删除,请三思而后行。",
|
||||
"accountDeletionRequested": "已请求删除账号,检查你的收件箱来确认请求。",
|
||||
"slideToConfirm": "滑动来确认",
|
||||
"serviceStatus": "服务状态",
|
||||
"firstBootTime": "首次启动于 @time",
|
||||
"rateTheApp": "给应用评分",
|
||||
"rateTheAppDesc": "在 App Store 上给 Solar Network 评分,让我们更好地为您服务吧!",
|
||||
"friendAdd": "添加好友",
|
||||
"blockUser": "屏蔽用户",
|
||||
"unblockUser": "解除屏蔽用户",
|
||||
"learnMoreAboutPerson": "了解关于 TA 的更多",
|
||||
"global": "全局",
|
||||
"all": "全部",
|
||||
"unablePreview": "无法预览",
|
||||
"dashboardNav": "仪表盘",
|
||||
"accountNav": "您",
|
||||
"performance": "性能",
|
||||
"animatedMessageList": "无动画消息列表",
|
||||
"animatedMessageListDesc": "在消息列表中禁用动画效果",
|
||||
"theme": "主题",
|
||||
"globalTheme": "全局应用主题",
|
||||
"agedTheme": "过时主题",
|
||||
"agedThemeDesc": "将全局主题降级为 Material Design 2,可能发生意料之外的问题,仅供实验使用",
|
||||
"appBackgroundImage": "全局背景图片",
|
||||
"appBackgroundImageDesc": "全局背景图片将会在所有页面中展示",
|
||||
"authPreferences": "安全偏好设置",
|
||||
"authPreferencesDesc": "调整账号的安全行为模式",
|
||||
"authMaximumAuthSteps": "最大认证步数",
|
||||
"authMaximumAuthStepsDesc": "登陆时最多的验证步数,值越高则越安全,反之则会相对方便;默认设置为 2",
|
||||
"auditLog": "活动日志",
|
||||
"shareImage": "分享图片",
|
||||
"shareImageFooter": "上 Solar Network 看更多有趣帖子",
|
||||
"fileSavedAt": "文件保存于 @path",
|
||||
"showIp": "显示 IP 地址",
|
||||
"shotOn": "由 @device 拍摄",
|
||||
"unread": "未读",
|
||||
"searchTook": "耗时 @time",
|
||||
"searchResult": "匹配到 @count 条结果",
|
||||
"happyBirthday": "生日快乐,@name!",
|
||||
"happyBirthdayDesc": "今天是你的第 @count 个生日"
|
||||
}
|
7
build.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
targets:
|
||||
$default:
|
||||
builders:
|
||||
json_serializable:
|
||||
options:
|
||||
explicit_to_json: true
|
||||
field_rename: snake
|
@ -1,4 +1,5 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
- provider: true
|
||||
- provider: true
|
||||
- drift: true
|
402
ios/Podfile.lock
@ -38,154 +38,193 @@ PODS:
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Firebase/Analytics (10.29.0):
|
||||
- file_saver (0.0.1):
|
||||
- Flutter
|
||||
- Firebase/Analytics (11.2.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Core (10.29.0):
|
||||
- Firebase/Core (11.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (~> 10.29.0)
|
||||
- Firebase/CoreOnly (10.29.0):
|
||||
- FirebaseCore (= 10.29.0)
|
||||
- Firebase/Crashlytics (10.29.0):
|
||||
- FirebaseAnalytics (~> 11.2.0)
|
||||
- Firebase/CoreOnly (11.2.0):
|
||||
- FirebaseCore (= 11.2.0)
|
||||
- Firebase/Crashlytics (11.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseCrashlytics (~> 10.29.0)
|
||||
- Firebase/Messaging (10.29.0):
|
||||
- FirebaseCrashlytics (~> 11.2.0)
|
||||
- Firebase/Messaging (11.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 10.29.0)
|
||||
- firebase_analytics (11.2.1):
|
||||
- Firebase/Analytics (= 10.29.0)
|
||||
- FirebaseMessaging (~> 11.2.0)
|
||||
- Firebase/Performance (11.2.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebasePerformance (~> 11.2.0)
|
||||
- firebase_analytics (11.3.3):
|
||||
- Firebase/Analytics (= 11.2.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_core (3.3.0):
|
||||
- Firebase/CoreOnly (= 10.29.0)
|
||||
- firebase_core (3.6.0):
|
||||
- Firebase/CoreOnly (= 11.2.0)
|
||||
- Flutter
|
||||
- firebase_crashlytics (4.0.4):
|
||||
- Firebase/Crashlytics (= 10.29.0)
|
||||
- firebase_crashlytics (4.1.3):
|
||||
- Firebase/Crashlytics (= 11.2.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_messaging (15.0.4):
|
||||
- Firebase/Messaging (= 10.29.0)
|
||||
- firebase_messaging (15.1.3):
|
||||
- Firebase/Messaging (= 11.2.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseAnalytics (10.29.0):
|
||||
- FirebaseAnalytics/AdIdSupport (= 10.29.0)
|
||||
- FirebaseCore (~> 10.0)
|
||||
- FirebaseInstallations (~> 10.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.11)
|
||||
- GoogleUtilities/Network (~> 7.11)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.11)"
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- FirebaseAnalytics/AdIdSupport (10.29.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- FirebaseInstallations (~> 10.0)
|
||||
- GoogleAppMeasurement (= 10.29.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.11)
|
||||
- GoogleUtilities/Network (~> 7.11)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.11)"
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- FirebaseCore (10.29.0):
|
||||
- FirebaseCoreInternal (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 7.12)
|
||||
- GoogleUtilities/Logger (~> 7.12)
|
||||
- FirebaseCoreExtension (10.29.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- FirebaseCoreInternal (10.29.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.8)"
|
||||
- FirebaseCrashlytics (10.29.0):
|
||||
- FirebaseCore (~> 10.5)
|
||||
- FirebaseInstallations (~> 10.0)
|
||||
- FirebaseRemoteConfigInterop (~> 10.23)
|
||||
- FirebaseSessions (~> 10.5)
|
||||
- GoogleDataTransport (~> 9.2)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- PromisesObjC (~> 2.1)
|
||||
- FirebaseInstallations (10.29.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
||||
- PromisesObjC (~> 2.1)
|
||||
- FirebaseMessaging (10.29.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- FirebaseInstallations (~> 10.0)
|
||||
- GoogleDataTransport (~> 9.3)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- GoogleUtilities/Reachability (~> 7.8)
|
||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- FirebaseRemoteConfigInterop (10.29.0)
|
||||
- FirebaseSessions (10.29.0):
|
||||
- FirebaseCore (~> 10.5)
|
||||
- FirebaseCoreExtension (~> 10.0)
|
||||
- FirebaseInstallations (~> 10.0)
|
||||
- GoogleDataTransport (~> 9.2)
|
||||
- GoogleUtilities/Environment (~> 7.13)
|
||||
- GoogleUtilities/UserDefaults (~> 7.13)
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- firebase_performance (0.10.0-8):
|
||||
- Firebase/Performance (= 11.2.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseABTesting (11.3.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseAnalytics (11.2.0):
|
||||
- FirebaseAnalytics/AdIdSupport (= 11.2.0)
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.0)
|
||||
- GoogleUtilities/Network (~> 8.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseAnalytics/AdIdSupport (11.2.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- GoogleAppMeasurement (= 11.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.0)
|
||||
- GoogleUtilities/Network (~> 8.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseCore (11.2.0):
|
||||
- FirebaseCoreInternal (~> 11.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/Logger (~> 8.0)
|
||||
- FirebaseCoreExtension (11.3.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseCoreInternal (11.3.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- FirebaseCrashlytics (11.2.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- FirebaseRemoteConfigInterop (~> 11.0)
|
||||
- FirebaseSessions (~> 11.0)
|
||||
- GoogleDataTransport (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseInstallations (11.3.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseMessaging (11.2.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- GoogleDataTransport (~> 10.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/Reachability (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebasePerformance (11.2.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- FirebaseRemoteConfig (~> 11.0)
|
||||
- FirebaseSessions (~> 11.0)
|
||||
- GoogleDataTransport (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseRemoteConfig (11.3.0):
|
||||
- FirebaseABTesting (~> 11.0)
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- FirebaseRemoteConfigInterop (~> 11.0)
|
||||
- FirebaseSharedSwift (~> 11.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- FirebaseRemoteConfigInterop (11.3.0)
|
||||
- FirebaseSessions (11.3.0):
|
||||
- FirebaseCore (~> 11.0)
|
||||
- FirebaseCoreExtension (~> 11.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- GoogleDataTransport (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesSwift (~> 2.1)
|
||||
- FirebaseSharedSwift (11.3.0)
|
||||
- Flutter (1.0.0)
|
||||
- flutter_app_update (0.0.1):
|
||||
- Flutter
|
||||
- flutter_background_service_ios (0.0.3):
|
||||
- Flutter
|
||||
- flutter_keyboard_visibility (0.0.1):
|
||||
- Flutter
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- Flutter
|
||||
- flutter_native_splash (0.0.1):
|
||||
- Flutter
|
||||
- flutter_secure_storage (6.0.0):
|
||||
- Flutter
|
||||
- flutter_udid (0.0.1):
|
||||
- Flutter
|
||||
- SAMKeychain
|
||||
- flutter_webrtc (0.11.3):
|
||||
- Flutter
|
||||
- WebRTC-SDK (= 125.6422.04)
|
||||
- gal (1.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- GoogleAppMeasurement (10.29.0):
|
||||
- GoogleAppMeasurement/AdIdSupport (= 10.29.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.11)
|
||||
- GoogleUtilities/Network (~> 7.11)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.11)"
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- GoogleAppMeasurement/AdIdSupport (10.29.0):
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (= 10.29.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.11)
|
||||
- GoogleUtilities/Network (~> 7.11)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.11)"
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (10.29.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.11)
|
||||
- GoogleUtilities/Network (~> 7.11)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.11)"
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- GoogleDataTransport (9.4.1):
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- nanopb (< 2.30911.0, >= 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.13.3):
|
||||
- GoogleAppMeasurement (11.2.0):
|
||||
- GoogleAppMeasurement/AdIdSupport (= 11.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.0)
|
||||
- GoogleUtilities/Network (~> 8.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/AdIdSupport (11.2.0):
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (= 11.2.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.0)
|
||||
- GoogleUtilities/Network (~> 8.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (11.2.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.0)
|
||||
- GoogleUtilities/Network (~> 8.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleDataTransport (10.1.0):
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- GoogleUtilities/AppDelegateSwizzler (8.0.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Environment (7.13.3):
|
||||
- GoogleUtilities/Environment (8.0.2):
|
||||
- GoogleUtilities/Privacy
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/Logger (7.13.3):
|
||||
- GoogleUtilities/Logger (8.0.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/MethodSwizzler (7.13.3):
|
||||
- GoogleUtilities/MethodSwizzler (8.0.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Network (7.13.3):
|
||||
- GoogleUtilities/Network (8.0.2):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (7.13.3)":
|
||||
- "GoogleUtilities/NSData+zlib (8.0.2)":
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Privacy (7.13.3)
|
||||
- GoogleUtilities/Reachability (7.13.3):
|
||||
- GoogleUtilities/Privacy (8.0.2)
|
||||
- GoogleUtilities/Reachability (8.0.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/UserDefaults (7.13.3):
|
||||
- GoogleUtilities/UserDefaults (8.0.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- image_cropper (0.0.4):
|
||||
@ -193,7 +232,9 @@ PODS:
|
||||
- TOCropViewController (~> 2.7.4)
|
||||
- image_picker_ios (0.0.1):
|
||||
- Flutter
|
||||
- livekit_client (2.2.4):
|
||||
- in_app_review (0.2.0):
|
||||
- Flutter
|
||||
- livekit_client (2.2.6):
|
||||
- Flutter
|
||||
- WebRTC-SDK (= 125.6422.04)
|
||||
- media_kit_libs_ios_video (1.0.4):
|
||||
@ -202,11 +243,11 @@ PODS:
|
||||
- Flutter
|
||||
- media_kit_video (0.0.1):
|
||||
- Flutter
|
||||
- nanopb (2.30910.0):
|
||||
- nanopb/decode (= 2.30910.0)
|
||||
- nanopb/encode (= 2.30910.0)
|
||||
- nanopb/decode (2.30910.0)
|
||||
- nanopb/encode (2.30910.0)
|
||||
- nanopb (3.30910.0):
|
||||
- nanopb/decode (= 3.30910.0)
|
||||
- nanopb/encode (= 3.30910.0)
|
||||
- nanopb/decode (3.30910.0)
|
||||
- nanopb/encode (3.30910.0)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- pasteboard (0.0.1):
|
||||
@ -223,19 +264,38 @@ PODS:
|
||||
- PromisesObjC (= 2.4.0)
|
||||
- protocol_handler_ios (0.0.1):
|
||||
- Flutter
|
||||
- SAMKeychain (1.5.3)
|
||||
- screen_brightness_ios (0.1.0):
|
||||
- Flutter
|
||||
- SDWebImage (5.19.6):
|
||||
- SDWebImage/Core (= 5.19.6)
|
||||
- SDWebImage/Core (5.19.6)
|
||||
- SDWebImage (5.19.7):
|
||||
- SDWebImage/Core (= 5.19.7)
|
||||
- SDWebImage/Core (5.19.7)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqflite (0.0.3):
|
||||
- sqflite_darwin (0.0.4):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- "sqlite3 (3.46.1+1)":
|
||||
- "sqlite3/common (= 3.46.1+1)"
|
||||
- "sqlite3/common (3.46.1+1)"
|
||||
- "sqlite3/dbstatvtab (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/fts5 (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/perf-threadsafe (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/rtree (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
- "sqlite3 (~> 3.46.0+1)"
|
||||
- sqlite3/dbstatvtab
|
||||
- sqlite3/fts5
|
||||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
- SwiftyGif (5.4.5)
|
||||
- TOCropViewController (2.7.4)
|
||||
- url_launcher_ios (0.0.1):
|
||||
@ -250,17 +310,25 @@ DEPENDENCIES:
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- file_saver (from `.symlinks/plugins/file_saver/ios`)
|
||||
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- firebase_performance (from `.symlinks/plugins/firebase_performance/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
|
||||
- flutter_background_service_ios (from `.symlinks/plugins/flutter_background_service_ios/ios`)
|
||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
|
||||
- flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`)
|
||||
- gal (from `.symlinks/plugins/gal/darwin`)
|
||||
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
|
||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
||||
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
|
||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
||||
@ -274,7 +342,8 @@ DEPENDENCIES:
|
||||
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
@ -284,6 +353,7 @@ SPEC REPOS:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- Firebase
|
||||
- FirebaseABTesting
|
||||
- FirebaseAnalytics
|
||||
- FirebaseCore
|
||||
- FirebaseCoreExtension
|
||||
@ -291,15 +361,20 @@ SPEC REPOS:
|
||||
- FirebaseCrashlytics
|
||||
- FirebaseInstallations
|
||||
- FirebaseMessaging
|
||||
- FirebasePerformance
|
||||
- FirebaseRemoteConfig
|
||||
- FirebaseRemoteConfigInterop
|
||||
- FirebaseSessions
|
||||
- FirebaseSharedSwift
|
||||
- GoogleAppMeasurement
|
||||
- GoogleDataTransport
|
||||
- GoogleUtilities
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- PromisesSwift
|
||||
- SAMKeychain
|
||||
- SDWebImage
|
||||
- sqlite3
|
||||
- SwiftyGif
|
||||
- TOCropViewController
|
||||
- WebRTC-SDK
|
||||
@ -311,6 +386,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
file_saver:
|
||||
:path: ".symlinks/plugins/file_saver/ios"
|
||||
firebase_analytics:
|
||||
:path: ".symlinks/plugins/firebase_analytics/ios"
|
||||
firebase_core:
|
||||
@ -319,12 +396,24 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/firebase_crashlytics/ios"
|
||||
firebase_messaging:
|
||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||
firebase_performance:
|
||||
:path: ".symlinks/plugins/firebase_performance/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_app_update:
|
||||
:path: ".symlinks/plugins/flutter_app_update/ios"
|
||||
flutter_background_service_ios:
|
||||
:path: ".symlinks/plugins/flutter_background_service_ios/ios"
|
||||
flutter_keyboard_visibility:
|
||||
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
|
||||
flutter_local_notifications:
|
||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
flutter_native_splash:
|
||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||
flutter_secure_storage:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
flutter_udid:
|
||||
:path: ".symlinks/plugins/flutter_udid/ios"
|
||||
flutter_webrtc:
|
||||
:path: ".symlinks/plugins/flutter_webrtc/ios"
|
||||
gal:
|
||||
@ -333,6 +422,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/image_cropper/ios"
|
||||
image_picker_ios:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
in_app_review:
|
||||
:path: ".symlinks/plugins/in_app_review/ios"
|
||||
livekit_client:
|
||||
:path: ".symlinks/plugins/livekit_client/ios"
|
||||
media_kit_libs_ios_video:
|
||||
@ -359,8 +450,10 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
sqflite:
|
||||
:path: ".symlinks/plugins/sqflite/darwin"
|
||||
sqflite_darwin:
|
||||
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||
sqlite3_flutter_libs:
|
||||
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
volume_controller:
|
||||
@ -369,41 +462,53 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
|
||||
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
|
||||
connectivity_plus: 4c41c08fc6d7c91f63bc7aec70ffe3730b04f563
|
||||
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
Firebase: cec914dab6fd7b1bd8ab56ea07ce4e03dd251c2d
|
||||
firebase_analytics: 04491d1ee74c8e7c2330c96afc54188a969b06ee
|
||||
firebase_core: 57aeb91680e5d5e6df6b888064be7c785f146efb
|
||||
firebase_crashlytics: e3d3e0c99bad5aaab5908385133dea8ec344693f
|
||||
firebase_messaging: c862b3d2b973ecc769194dc8de09bd22c77ae757
|
||||
FirebaseAnalytics: 23717de130b779aa506e757edb9713d24b6ffeda
|
||||
FirebaseCore: 30e9c1cbe3d38f5f5e75f48bfcea87d7c358ec16
|
||||
FirebaseCoreExtension: 705ca5b14bf71d2564a0ddc677df1fc86ffa600f
|
||||
FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934
|
||||
FirebaseCrashlytics: 34647b41e18de773717fdd348a22206f2f9bc774
|
||||
FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd
|
||||
FirebaseMessaging: 7b5d8033e183ab59eb5b852a53201559e976d366
|
||||
FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d
|
||||
FirebaseSessions: dbd14adac65ce996228652c1fc3a3f576bdf3ecc
|
||||
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
||||
Firebase: 98e6bf5278170668a7983e12971a66b2cd57fc8c
|
||||
firebase_analytics: fbc57838bdb94eef1e0ff504f127d974ff2981ad
|
||||
firebase_core: 2bedc3136ec7c7b8561c6123ed0239387b53f2af
|
||||
firebase_crashlytics: 37d104d457b51760b48504a93a12b3bf70995d77
|
||||
firebase_messaging: 15d114e1a41fc31e4fbabcd48d765a19eec94a38
|
||||
firebase_performance: 26ad47755d3e8d7b04b9bb36bdfbf1cec8d8dfcc
|
||||
FirebaseABTesting: c4559fcd2eba9f6bdaf0599e2c37ded01c343e4c
|
||||
FirebaseAnalytics: c36efd5710c60c17558650fa58c2066eca7e9265
|
||||
FirebaseCore: a282032ae9295c795714ded2ec9c522fc237f8da
|
||||
FirebaseCoreExtension: 30bb063476ef66cd46925243d64ad8b2c8ac3264
|
||||
FirebaseCoreInternal: ac26d09a70c730e497936430af4e60fb0c68ec4e
|
||||
FirebaseCrashlytics: cfc69af5b53565dc6a5e563788809b5778ac4eac
|
||||
FirebaseInstallations: 58cf94dabf1e2bb2fa87725a9be5c2249171cda0
|
||||
FirebaseMessaging: c9ec7b90c399c7a6100297e9d16f8a27fc7f7152
|
||||
FirebasePerformance: c39138c0700b8ef6040f0b80b5707320808e2862
|
||||
FirebaseRemoteConfig: 5be2ca4f9870d475b39214210955fdaeecf7e5ca
|
||||
FirebaseRemoteConfigInterop: c3a5c31b3c22079f41ba1dc645df889d9ce38cb9
|
||||
FirebaseSessions: 655ff17f3cc1a635cbdc2d69b953878001f9e25b
|
||||
FirebaseSharedSwift: d39c2ad64a11a8d936ce25a42b00df47078bb59c
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_app_update: 65f61da626cb111d1b24674abc4b01728d7723bc
|
||||
flutter_background_service_ios: e30e0d3ee69e4cee66272d0c78eacd48c2e94aac
|
||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||
flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04
|
||||
flutter_webrtc: 75b868e4f9e817c7a9a42ca4b6169063de4eec9f
|
||||
gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1
|
||||
GoogleAppMeasurement: f9de05ee17401e3355f68e8fc8b5064d429f5918
|
||||
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
|
||||
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
|
||||
GoogleAppMeasurement: 76d4f8b36b03bd8381fa9a7fe2cc7f99c0a2e93a
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
||||
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
|
||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||
livekit_client: d079c5f040d4bf2b80440ff0ae997725a183e4bc
|
||||
in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d
|
||||
livekit_client: 20e01637431bc108dad451c8a11c1d206e1dd2cd
|
||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
||||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||
nanopb: 438bc412db1928dac798aa6fd75726007be04262
|
||||
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
@ -411,11 +516,14 @@ SPEC CHECKSUMS:
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||
protocol_handler_ios: a5db8abc38526ee326988b808be621e5fd568990
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
||||
SDWebImage: a79252b60f4678812d94316c91da69ec83089c9f
|
||||
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
||||
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqflite_darwin: a553b1fd6fe66f53bbb0fe5b4f5bab93f08d7a13
|
||||
sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb
|
||||
sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
|
@ -254,6 +254,7 @@
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
B1CDA9DD5B638A2BB88053CB /* [CP] Check Pods Manifest.lock */,
|
||||
7356FAC42C72724B0051A465 /* [Crashlytics] Clear dSYM */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
@ -263,7 +264,7 @@
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
287A33C298CA352A7E7F32A4 /* [CP] Embed Pods Frameworks */,
|
||||
0818E8E4321C0D7433E07576 /* [CP] Copy Pods Resources */,
|
||||
1A9FD6BE5DEE99CDA7399504 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
|
||||
1A9FD6BE5DEE99CDA7399504 /* [Crashlytics] Upload dSYM */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -366,7 +367,7 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
1A9FD6BE5DEE99CDA7399504 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
|
||||
1A9FD6BE5DEE99CDA7399504 /* [Crashlytics] Upload dSYM */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@ -375,14 +376,14 @@
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\"";
|
||||
name = "[Crashlytics] Upload dSYM";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\n#!/bin/bash\nPATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=$PODS_ROOT/FirebaseCrashlytics/upload-symbols --platform=ios --apple-project-path=${SRCROOT} --env-platform-name=${PLATFORM_NAME} --env-configuration=${CONFIGURATION} --env-project-dir=${PROJECT_DIR} --env-built-products-dir=${BUILT_PRODUCTS_DIR} --env-dwarf-dsym-folder-path=${DWARF_DSYM_FOLDER_PATH} --env-dwarf-dsym-file-name=${DWARF_DSYM_FILE_NAME} --env-infoplist-path=${INFOPLIST_PATH} --default-config=default\n";
|
||||
shellScript = "\n#!/bin/bash\nsleep 1 # Without this, there seems a chance that the script runs before dSYM generation is finished \n$PODS_ROOT/FirebaseCrashlytics/upload-symbols -gsp $PROJECT_DIR/Runner/GoogleService-Info.plist -p ios $DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME\n";
|
||||
};
|
||||
259653AE41D478F4C6BAE9B2 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@ -439,6 +440,24 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
7356FAC42C72724B0051A465 /* [Crashlytics] Clear dSYM */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[Crashlytics] Clear dSYM";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\n#!/bin/bash\nrm -rf $DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME\n";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@ -452,7 +471,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
|
||||
};
|
||||
B1CDA9DD5B638A2BB88053CB /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@ -597,6 +616,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
@ -901,6 +921,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
@ -928,6 +949,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
|
@ -59,6 +59,7 @@
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
showGraphicsOverview = "Yes"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
|
22
ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "background.png",
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "darkbackground.png",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png
vendored
Normal file
After Width: | Height: | Size: 69 B |
BIN
ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png
vendored
Normal file
After Width: | Height: | Size: 69 B |
@ -1,23 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 233 KiB |
@ -16,13 +16,19 @@
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
|
||||
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
|
||||
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
@ -32,6 +38,7 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
<image name="LaunchImage" width="1026" height="1024"/>
|
||||
<image name="LaunchBackground" width="1" height="1"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
@ -81,5 +81,11 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CFBundleLocalizations</key>
|
||||
<array>
|
||||
<string>en</string>
|
||||
</array>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
109
lib/background.dart
Normal file
@ -0,0 +1,109 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart' hide Notification;
|
||||
import 'package:flutter_background_service/flutter_background_service.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:solian/models/notification.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
|
||||
FlutterBackgroundService? bgNotificationService;
|
||||
|
||||
void autoConfigureBackgroundNotificationService() async {
|
||||
if (bgNotificationService != null) return;
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool('service_background_notification') != true) return;
|
||||
|
||||
bgNotificationService = FlutterBackgroundService();
|
||||
|
||||
await bgNotificationService!.configure(
|
||||
androidConfiguration: AndroidConfiguration(
|
||||
onStart: onBackgroundNotificationServiceStart,
|
||||
autoStart: true,
|
||||
autoStartOnBoot: true,
|
||||
isForegroundMode: false,
|
||||
),
|
||||
// This feature won't be able to use on iOS
|
||||
// We got APNs support covered
|
||||
iosConfiguration: IosConfiguration(
|
||||
autoStart: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void autoStartBackgroundNotificationService() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool('service_background_notification') != true) return;
|
||||
if (bgNotificationService == null) return;
|
||||
bgNotificationService!.startService();
|
||||
}
|
||||
|
||||
void autoStopBackgroundNotificationService() async {
|
||||
if (bgNotificationService == null) return;
|
||||
if (await bgNotificationService!.isRunning()) {
|
||||
bgNotificationService?.invoke('stopService');
|
||||
}
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void onBackgroundNotificationServiceStart(ServiceInstance service) async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
DartPluginRegistrant.ensureInitialized();
|
||||
|
||||
Get.put(AuthProvider());
|
||||
Get.put(WebSocketProvider());
|
||||
|
||||
service.on('stopService').listen((event) {
|
||||
service.stopSelf();
|
||||
});
|
||||
|
||||
final auth = Get.find<AuthProvider>();
|
||||
await auth.refreshAuthorizeStatus();
|
||||
await auth.ensureCredentials();
|
||||
if (!auth.isAuthorized.value) {
|
||||
debugPrint(
|
||||
'Background notification do nothing due to user didn\'t sign in.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const notificationChannelId = 'solian_notification_service';
|
||||
|
||||
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
final ws = Get.find<WebSocketProvider>();
|
||||
await ws.connect();
|
||||
debugPrint('Background notification has been started');
|
||||
ws.stream.stream.listen(
|
||||
(event) {
|
||||
debugPrint(
|
||||
'Background notification service incoming message: ${event.method} ${event.message}',
|
||||
);
|
||||
|
||||
if (event.method == 'notifications.new' && event.payload != null) {
|
||||
final data = Notification.fromJson(event.payload!);
|
||||
debugPrint(
|
||||
'Background notification service got a notification id=${data.id}',
|
||||
);
|
||||
flutterLocalNotificationsPlugin.show(
|
||||
data.id,
|
||||
data.title,
|
||||
[data.subtitle, data.body].where((x) => x != null).join('\n'),
|
||||
const NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
notificationChannelId,
|
||||
'Solian Notification Service',
|
||||
channelDescription: 'Notifications that sent via Solar Network',
|
||||
importance: Importance.high,
|
||||
icon: 'mipmap/ic_launcher',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
@ -1,18 +1,34 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:confetti/confetti.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:in_app_review/in_app_review.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:solian/exceptions/request.dart';
|
||||
import 'package:solian/exts.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/content/channel.dart';
|
||||
import 'package:solian/providers/content/realm.dart';
|
||||
import 'package:solian/providers/notifications.dart';
|
||||
import 'package:solian/providers/relation.dart';
|
||||
import 'package:solian/providers/stickers.dart';
|
||||
import 'package:solian/providers/theme_switcher.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/services.dart';
|
||||
import 'package:solian/widgets/root_container.dart';
|
||||
import 'package:solian/widgets/sized_container.dart';
|
||||
import 'package:flutter_app_update/flutter_app_update.dart';
|
||||
import 'package:version/version.dart';
|
||||
|
||||
enum BootstrapperSpecialState {
|
||||
userBirthday,
|
||||
appAnniversary,
|
||||
}
|
||||
|
||||
class BootstrapperShell extends StatefulWidget {
|
||||
final Widget child;
|
||||
@ -34,6 +50,111 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
|
||||
int _periodCursor = 0;
|
||||
|
||||
// Special state is some special event triggered after bootstrapping
|
||||
BootstrapperSpecialState? _specialState;
|
||||
|
||||
final Completer _bootCompleter = Completer();
|
||||
|
||||
void _requestRating() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.containsKey('first_boot_time')) {
|
||||
final rawTime = prefs.getString('first_boot_time');
|
||||
final time = DateTime.tryParse(rawTime ?? '');
|
||||
if (time != null &&
|
||||
time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) {
|
||||
final inAppReview = InAppReview.instance;
|
||||
if (prefs.getBool('rating_requested') == true) return;
|
||||
if (await inAppReview.isAvailable()) {
|
||||
await inAppReview.requestReview();
|
||||
prefs.setBool('rating_requested', true);
|
||||
} else {
|
||||
log('Unable request app review, unavailable');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prefs.setString('first_boot_time', DateTime.now().toIso8601String());
|
||||
}
|
||||
}
|
||||
|
||||
void _updateNow(String localVersionString, String remoteVersionString) {
|
||||
context
|
||||
.showConfirmDialog(
|
||||
'updateAvailable'.tr,
|
||||
'updateAvailableDesc'.trParams({
|
||||
'from': localVersionString,
|
||||
'to': remoteVersionString,
|
||||
}),
|
||||
)
|
||||
.then((result) {
|
||||
if (result) {
|
||||
final model = UpdateModel(
|
||||
'https://files.solsynth.dev/d/production01/solian/app-arm64-v8a-release.apk',
|
||||
'solian-app-arm64-v8a-release.apk',
|
||||
'ic_launcher',
|
||||
'https://testflight.apple.com/join/YJ0lmN6O',
|
||||
);
|
||||
AzhonAppUpdate.update(model);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _checkForUpdate() async {
|
||||
if (PlatformInfo.isWeb) return;
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
final localVersionString = '${info.version}+${info.buildNumber}';
|
||||
final resp = await GetConnect(
|
||||
timeout: const Duration(seconds: 60),
|
||||
).get(
|
||||
'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?page=1&limit=1',
|
||||
);
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
}
|
||||
final remoteVersionString =
|
||||
(resp.body as List).firstOrNull?['name'] ?? '0.0.0+0';
|
||||
final remoteVersion = Version.parse(remoteVersionString.split('+').first);
|
||||
final localVersion = Version.parse(localVersionString.split('+').first);
|
||||
final remoteBuildNumber =
|
||||
int.tryParse(remoteVersionString.split('+').last) ?? 0;
|
||||
final localBuildNumber =
|
||||
int.tryParse(localVersionString.split('+').last) ?? 0;
|
||||
final strictUpdate = prefs.getBool('check_update_strictly') ?? false;
|
||||
if (remoteVersion > localVersion ||
|
||||
(remoteVersion == localVersion &&
|
||||
remoteBuildNumber > localBuildNumber) ||
|
||||
(remoteVersionString != localVersionString && strictUpdate)) {
|
||||
if (PlatformInfo.isAndroid) {
|
||||
_updateNow(localVersionString, remoteVersionString);
|
||||
} else {
|
||||
context.showInfoDialog(
|
||||
'updateAvailable'.tr,
|
||||
'bsCheckForUpdateDesc'.tr,
|
||||
);
|
||||
}
|
||||
} else if (remoteVersionString != localVersionString) {
|
||||
_bootCompleter.future.then((_) {
|
||||
context.showSnackbar(
|
||||
'updateMayAvailable'.trParams({
|
||||
'version': remoteVersionString,
|
||||
}),
|
||||
action: PlatformInfo.isAndroid
|
||||
? SnackBarAction(
|
||||
label: 'updateNow'.tr,
|
||||
onPressed: () {
|
||||
_updateNow(localVersionString, remoteVersionString);
|
||||
},
|
||||
)
|
||||
: null,
|
||||
);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
context.showErrorDialog('Unable to check update: $e');
|
||||
}
|
||||
}
|
||||
|
||||
late final List<({String label, Future<void> Function() action})> _periods = [
|
||||
(
|
||||
label: 'bsLoadingTheme',
|
||||
@ -41,36 +162,10 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
await context.read<ThemeSwitcher>().restoreTheme();
|
||||
},
|
||||
),
|
||||
(
|
||||
label: 'bsCheckForUpdate',
|
||||
action: () async {
|
||||
if (PlatformInfo.isWeb) return;
|
||||
try {
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
final localVersionString = '${info.version}+${info.buildNumber}';
|
||||
final resp = await GetConnect().get(
|
||||
'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?limit=1',
|
||||
);
|
||||
if (resp.body[0]['name'] != localVersionString) {
|
||||
setState(() {
|
||||
_isErrored = true;
|
||||
_subtitle = PlatformInfo.isIOS || PlatformInfo.isMacOS
|
||||
? 'bsCheckForUpdateDescApple'.tr
|
||||
: 'bsCheckForUpdateDescCommon'.tr;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_isErrored = true;
|
||||
_subtitle = 'bsCheckForUpdateFailed'.tr;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
label: 'bsCheckingServer',
|
||||
action: () async {
|
||||
final client = ServiceFinder.configureClient('dealer');
|
||||
final client = await ServiceFinder.configureClient('dealer');
|
||||
final resp = await client.get('/.well-known');
|
||||
if (resp.statusCode != null && resp.statusCode != 200) {
|
||||
setState(() {
|
||||
@ -112,15 +207,31 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
label: 'bsPreparingData',
|
||||
action: () async {
|
||||
final AuthProvider auth = Get.find();
|
||||
await Future.wait([
|
||||
Get.find<StickerProvider>().refreshAvailableStickers(),
|
||||
if (auth.isAuthorized.isTrue)
|
||||
Get.find<ChannelProvider>().refreshAvailableChannel(),
|
||||
if (auth.isAuthorized.isTrue)
|
||||
Get.find<RelationshipProvider>().refreshRelativeList(),
|
||||
if (auth.isAuthorized.isTrue)
|
||||
Get.find<RealmProvider>().refreshAvailableRealms(),
|
||||
]);
|
||||
try {
|
||||
await Future.wait([
|
||||
if (auth.isAuthorized.isTrue)
|
||||
Get.find<NotificationProvider>().fetchNotification(),
|
||||
if (auth.isAuthorized.isTrue)
|
||||
Get.find<RelationshipProvider>().refreshRelativeList(),
|
||||
if (auth.isAuthorized.isTrue)
|
||||
Get.find<RealmProvider>().refreshAvailableRealms(),
|
||||
]);
|
||||
|
||||
if (auth.isAuthorized.isTrue && auth.userProfile.value != null) {
|
||||
final account = Account.fromJson(auth.userProfile.value!);
|
||||
if (account.profile?.birthday != null) {
|
||||
final birthDate = account.profile!.birthday!.toLocal();
|
||||
final isBirthday = birthDate.day == DateTime.now().day;
|
||||
if (isBirthday) {
|
||||
setState(
|
||||
() => _specialState = BootstrapperSpecialState.userBirthday,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
context.showErrorDialog(e);
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
@ -129,7 +240,7 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isTrue) {
|
||||
try {
|
||||
Get.find<WebSocketProvider>().registerPushNotifications();
|
||||
Get.find<NotificationProvider>().registerPushNotifications();
|
||||
} catch (err) {
|
||||
context.showSnackbar(
|
||||
'pushNotifyRegisterFailed'.trParams({'reason': err.toString()}),
|
||||
@ -151,6 +262,9 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
}
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
_bootCompleter.complete();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,14 +272,17 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
_runPeriods();
|
||||
_checkForUpdate();
|
||||
_bootCompleter.future.then((_) {
|
||||
_requestRating();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_isBusy || _isErrored) {
|
||||
return GestureDetector(
|
||||
child: Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: RootContainer(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
@ -193,7 +310,7 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(strokeWidth: 3),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Gap(12),
|
||||
CenteredContainer(
|
||||
maxWidth: 280,
|
||||
child: Column(
|
||||
@ -248,6 +365,9 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
_isBusy = false;
|
||||
_isErrored = false;
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
_bootCompleter.complete();
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_isBusy = true;
|
||||
@ -258,8 +378,142 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
}
|
||||
},
|
||||
);
|
||||
} else if (_specialState != null) {
|
||||
return GestureDetector(
|
||||
child: RootContainer(
|
||||
child: switch (_specialState) {
|
||||
BootstrapperSpecialState.appAnniversary => const Placeholder(),
|
||||
_ => _BirthdaySpecialScreen(),
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
setState(() => _specialState = null);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return widget.child;
|
||||
}
|
||||
}
|
||||
|
||||
class _BirthdaySpecialScreen extends StatefulWidget {
|
||||
const _BirthdaySpecialScreen();
|
||||
|
||||
@override
|
||||
State<_BirthdaySpecialScreen> createState() => _BirthdaySpecialScreenState();
|
||||
}
|
||||
|
||||
class _BirthdaySpecialScreenState extends State<_BirthdaySpecialScreen> {
|
||||
late final ConfettiController _confettiController =
|
||||
ConfettiController(duration: const Duration(seconds: 10));
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_confettiController.play();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_confettiController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Color get _unFocusColor =>
|
||||
Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
|
||||
|
||||
String _toOrdinal(int num) {
|
||||
if (num >= 11 && num <= 13) {
|
||||
return '${num}th';
|
||||
}
|
||||
|
||||
switch (num % 10) {
|
||||
case 1:
|
||||
return '${num}st';
|
||||
case 2:
|
||||
return '${num}nd';
|
||||
case 3:
|
||||
return '${num}rd';
|
||||
default:
|
||||
return '${num}th';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AuthProvider auth = Get.find();
|
||||
final account = Account.fromJson(auth.userProfile.value!);
|
||||
|
||||
final birthDate = account.profile!.birthday!.toLocal();
|
||||
final birthdayCount = DateTime.now().difference(birthDate).inDays ~/ 365;
|
||||
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: ConfettiWidget(
|
||||
confettiController: _confettiController,
|
||||
blastDirectionality: BlastDirectionality.explosive,
|
||||
shouldLoop: true,
|
||||
colors: const [
|
||||
Colors.green,
|
||||
Colors.blue,
|
||||
Colors.pink,
|
||||
Colors.orange,
|
||||
Colors.purple
|
||||
],
|
||||
maxBlastForce: 30,
|
||||
minBlastForce: 15,
|
||||
emissionFrequency: 0.05,
|
||||
numberOfParticles: 20,
|
||||
gravity: 0.2,
|
||||
),
|
||||
),
|
||||
Align(
|
||||
child: CenteredContainer(
|
||||
maxWidth: 320,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'🎂',
|
||||
style: TextStyle(fontSize: 60),
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'happyBirthday'.trParams({
|
||||
'name': account.profile?.firstName != null
|
||||
? [
|
||||
account.profile?.firstName,
|
||||
account.profile?.lastName
|
||||
].join(' ')
|
||||
: '@${account.name}',
|
||||
}),
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
Text(
|
||||
'happyBirthdayDesc'.trParams({
|
||||
'count': _toOrdinal(birthdayCount),
|
||||
}),
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'bsContinuable'.tr,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: _unFocusColor,
|
||||
),
|
||||
).paddingOnly(bottom: 5),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,112 +1,87 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:solian/models/channel.dart';
|
||||
import 'package:solian/models/event.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
import 'package:solian/providers/message/adaptor.dart';
|
||||
import 'package:solian/providers/message/events.dart';
|
||||
import 'package:solian/providers/database/database.dart';
|
||||
import 'package:solian/providers/database/services/messages.dart';
|
||||
|
||||
class ChatEventController {
|
||||
late final MessageHistoryDb database;
|
||||
late final MessagesFetchingProvider src;
|
||||
|
||||
final RxList<LocalEvent> currentEvents = RxList.empty(growable: true);
|
||||
final RxList<LocalMessageEventTableData> currentEvents =
|
||||
RxList.empty(growable: true);
|
||||
final RxInt totalEvents = 0.obs;
|
||||
|
||||
final RxBool isLoading = false.obs;
|
||||
final RxBool isLoading = true.obs;
|
||||
|
||||
Channel? channel;
|
||||
String? scope;
|
||||
|
||||
Future<void> initialize() async {
|
||||
if (!PlatformInfo.isWeb) {
|
||||
database = await createHistoryDb();
|
||||
}
|
||||
src = Get.find();
|
||||
currentEvents.clear();
|
||||
}
|
||||
|
||||
Future<LocalEvent?> getEvent(int id) async {
|
||||
Future<LocalMessageEventTableData?> getEvent(int id) async {
|
||||
if (channel == null || scope == null) return null;
|
||||
|
||||
if (PlatformInfo.isWeb) {
|
||||
final remoteRecord = await getRemoteEvent(id, channel!, scope!);
|
||||
if (remoteRecord == null) return null;
|
||||
return LocalEvent(
|
||||
remoteRecord.id,
|
||||
remoteRecord,
|
||||
remoteRecord.channelId,
|
||||
remoteRecord.createdAt,
|
||||
);
|
||||
} else {
|
||||
return await database.getEvent(id, channel!, scope: scope!);
|
||||
}
|
||||
return await src.getEvent(id, channel!, scope: scope!);
|
||||
}
|
||||
|
||||
Future<void> getEvents(Channel channel, String scope) async {
|
||||
Future<void> getInitialEvents(Channel channel, String scope) async {
|
||||
this.channel = channel;
|
||||
this.scope = scope;
|
||||
|
||||
syncLocal(channel);
|
||||
const firstTake = 20;
|
||||
const furtherTake = 100;
|
||||
|
||||
isLoading.value = true;
|
||||
if (PlatformInfo.isWeb) {
|
||||
final result = await getRemoteEvents(
|
||||
channel,
|
||||
scope,
|
||||
remainDepth: 3,
|
||||
offset: 0,
|
||||
);
|
||||
totalEvents.value = result?.$2 ?? 0;
|
||||
if (result != null) {
|
||||
for (final x in result.$1.reversed) {
|
||||
final entry = LocalEvent(x.id, x, x.channelId, x.createdAt);
|
||||
insertEvent(entry);
|
||||
applyEvent(entry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final result = await database.syncRemoteEvents(
|
||||
channel,
|
||||
scope: scope,
|
||||
);
|
||||
totalEvents.value = result?.$2 ?? 0;
|
||||
await syncLocal(channel);
|
||||
}
|
||||
await syncLocal(channel, take: firstTake);
|
||||
isLoading.value = false;
|
||||
|
||||
// Take a small range of messages to check is local database up to date
|
||||
var isUpToDate = true;
|
||||
final result =
|
||||
await src.pullRemoteEvents(channel, scope: scope, take: firstTake);
|
||||
totalEvents.value = result?.$2 ?? 0;
|
||||
if ((result?.$1.length ?? 0) > 0) {
|
||||
final minId = result!.$1.map((x) => x.id).reduce(math.min);
|
||||
isUpToDate = await src.getEventFromLocal(minId) != null;
|
||||
}
|
||||
syncLocal(channel, take: firstTake);
|
||||
|
||||
if (!isUpToDate) {
|
||||
// Loading more content due to isn't up to date
|
||||
final result =
|
||||
await src.pullRemoteEvents(channel, scope: scope, take: furtherTake);
|
||||
totalEvents.value = result?.$2 ?? 0;
|
||||
syncLocal(channel, take: furtherTake);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadEvents(Channel channel, String scope) async {
|
||||
const take = 20;
|
||||
final offset = currentEvents.length;
|
||||
|
||||
isLoading.value = true;
|
||||
if (PlatformInfo.isWeb) {
|
||||
final result = await getRemoteEvents(
|
||||
channel,
|
||||
scope,
|
||||
remainDepth: 3,
|
||||
offset: currentEvents.length,
|
||||
);
|
||||
if (result != null) {
|
||||
totalEvents.value = result.$2;
|
||||
for (final x in result.$1.reversed) {
|
||||
final entry = LocalEvent(x.id, x, x.channelId, x.createdAt);
|
||||
currentEvents.add(entry);
|
||||
applyEvent(entry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final result = await database.syncRemoteEvents(
|
||||
channel,
|
||||
depth: 3,
|
||||
scope: scope,
|
||||
offset: currentEvents.length,
|
||||
);
|
||||
await syncLocal(channel, take: take, offset: offset);
|
||||
src
|
||||
.pullRemoteEvents(channel, scope: scope, take: take, offset: offset)
|
||||
.then((result) {
|
||||
totalEvents.value = result?.$2 ?? 0;
|
||||
await syncLocal(channel);
|
||||
}
|
||||
syncLocal(channel, take: take, offset: offset);
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<bool> syncLocal(Channel channel) async {
|
||||
if (PlatformInfo.isWeb) return false;
|
||||
final data = await database.localEvents.findAllByChannel(channel.id);
|
||||
currentEvents.replaceRange(0, currentEvents.length, data);
|
||||
Future<bool> syncLocal(Channel channel,
|
||||
{required int take, int offset = 0}) async {
|
||||
final data = await src.listEvents(channel, take: take, offset: offset);
|
||||
if (currentEvents.length >= offset + take) {
|
||||
currentEvents.replaceRange(offset, offset + take, data);
|
||||
} else {
|
||||
currentEvents.insertAll(currentEvents.length, data);
|
||||
}
|
||||
for (final x in data.reversed) {
|
||||
applyEvent(x);
|
||||
}
|
||||
@ -114,26 +89,20 @@ class ChatEventController {
|
||||
}
|
||||
|
||||
receiveEvent(Event remote) async {
|
||||
LocalEvent entry;
|
||||
if (PlatformInfo.isWeb) {
|
||||
entry = LocalEvent(
|
||||
remote.id,
|
||||
remote,
|
||||
remote.channelId,
|
||||
remote.createdAt,
|
||||
);
|
||||
} else {
|
||||
entry = await database.receiveEvent(remote);
|
||||
}
|
||||
LocalMessageEventTableData entry;
|
||||
entry = await src.receiveEvent(remote);
|
||||
|
||||
totalEvents.value++;
|
||||
insertEvent(entry);
|
||||
applyEvent(entry);
|
||||
}
|
||||
|
||||
insertEvent(LocalEvent entry) {
|
||||
void insertEvent(LocalMessageEventTableData entry) {
|
||||
if (entry.channelId != channel?.id) return;
|
||||
|
||||
final idx = currentEvents.indexWhere((x) => x.data.uuid == entry.data.uuid);
|
||||
final idx = currentEvents.indexWhere(
|
||||
(x) => x.data!.uuid == entry.data!.uuid,
|
||||
);
|
||||
if (idx != -1) {
|
||||
currentEvents[idx] = entry;
|
||||
} else {
|
||||
@ -141,36 +110,36 @@ class ChatEventController {
|
||||
}
|
||||
}
|
||||
|
||||
applyEvent(LocalEvent entry) {
|
||||
void applyEvent(LocalMessageEventTableData entry) {
|
||||
if (entry.channelId != channel?.id) return;
|
||||
|
||||
switch (entry.data.type) {
|
||||
switch (entry.data!.type) {
|
||||
case 'messages.edit':
|
||||
final body = EventMessageBody.fromJson(entry.data.body);
|
||||
final body = EventMessageBody.fromJson(entry.data!.body);
|
||||
if (body.relatedEvent != null) {
|
||||
final idx =
|
||||
currentEvents.indexWhere((x) => x.data.id == body.relatedEvent);
|
||||
currentEvents.indexWhere((x) => x.data!.id == body.relatedEvent);
|
||||
if (idx != -1) {
|
||||
currentEvents[idx].data.body = entry.data.body;
|
||||
currentEvents[idx].data.updatedAt = entry.data.updatedAt;
|
||||
currentEvents[idx].data!.body = entry.data!.body;
|
||||
currentEvents[idx].data!.updatedAt = entry.data!.updatedAt;
|
||||
}
|
||||
}
|
||||
case 'messages.delete':
|
||||
final body = EventMessageBody.fromJson(entry.data.body);
|
||||
final body = EventMessageBody.fromJson(entry.data!.body);
|
||||
if (body.relatedEvent != null) {
|
||||
currentEvents.removeWhere((x) => x.id == body.relatedEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addPendingEvent(Event info) async {
|
||||
Future<void> addPendingEvent(Event info) async {
|
||||
currentEvents.insert(
|
||||
0,
|
||||
LocalEvent(
|
||||
info.id,
|
||||
info,
|
||||
info.channelId,
|
||||
DateTime.now(),
|
||||
LocalMessageEventTableData(
|
||||
id: info.id,
|
||||
channelId: info.channelId,
|
||||
createdAt: DateTime.now(),
|
||||
data: info,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
class PostEditorController extends GetxController {
|
||||
late final SharedPreferences _prefs;
|
||||
|
||||
final aliasController = TextEditingController();
|
||||
final titleController = TextEditingController();
|
||||
final descriptionController = TextEditingController();
|
||||
final contentController = TextEditingController();
|
||||
@ -30,9 +31,9 @@ class PostEditorController extends GetxController {
|
||||
Rx<Realm?> realmZone = Rx(null);
|
||||
Rx<DateTime?> publishedAt = Rx(null);
|
||||
Rx<DateTime?> publishedUntil = Rx(null);
|
||||
RxList<int> attachments = RxList<int>.empty(growable: true);
|
||||
RxList<String> attachments = RxList<String>.empty(growable: true);
|
||||
RxList<String> tags = RxList<String>.empty(growable: true);
|
||||
Rx<int?> thumbnail = Rx(null);
|
||||
Rx<String?> thumbnail = Rx(null);
|
||||
|
||||
RxList<int> visibleUsers = RxList.empty(growable: true);
|
||||
RxList<int> invisibleUsers = RxList.empty(growable: true);
|
||||
@ -42,14 +43,17 @@ class PostEditorController extends GetxController {
|
||||
|
||||
RxBool isRestoreFromLocal = false.obs;
|
||||
Rx<DateTime?> lastSaveTime = Rx(null);
|
||||
Timer? _saveTimer;
|
||||
Future? _saveFuture;
|
||||
|
||||
PostEditorController() {
|
||||
SharedPreferences.getInstance().then((inst) {
|
||||
_prefs = inst;
|
||||
_saveTimer = Timer.periodic(
|
||||
const Duration(seconds: 3),
|
||||
(Timer t) {
|
||||
});
|
||||
contentController.addListener(() {
|
||||
contentLength.value = contentController.text.length;
|
||||
_saveFuture ??= Future.delayed(
|
||||
const Duration(seconds: 1),
|
||||
() {
|
||||
if (isNotEmpty) {
|
||||
localSave();
|
||||
lastSaveTime.value = DateTime.now();
|
||||
@ -58,12 +62,10 @@ class PostEditorController extends GetxController {
|
||||
localClear();
|
||||
lastSaveTime.value = null;
|
||||
}
|
||||
_saveFuture = null;
|
||||
},
|
||||
);
|
||||
});
|
||||
contentController.addListener(() {
|
||||
contentLength.value = contentController.text.length;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> editOverview(BuildContext context) {
|
||||
@ -115,14 +117,29 @@ class PostEditorController extends GetxController {
|
||||
return showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => AttachmentEditorPopup(
|
||||
usage: 'i.attachment',
|
||||
pool: 'interactive',
|
||||
initialAttachments: attachments,
|
||||
onAdd: (int value) {
|
||||
onAdd: (String value) {
|
||||
attachments.add(value);
|
||||
},
|
||||
onRemove: (int value) {
|
||||
onRemove: (String value) {
|
||||
attachments.remove(value);
|
||||
},
|
||||
onInsert: (String str) {
|
||||
final text = contentController.text;
|
||||
final selection = contentController.selection;
|
||||
final newText = text.replaceRange(
|
||||
selection.start,
|
||||
selection.end,
|
||||
str,
|
||||
);
|
||||
contentController.value = TextEditingValue(
|
||||
text: newText,
|
||||
selection: TextSelection.collapsed(
|
||||
offset: selection.baseOffset + str.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -154,13 +171,14 @@ class PostEditorController extends GetxController {
|
||||
);
|
||||
}
|
||||
|
||||
void localRead() {
|
||||
SharedPreferences.getInstance().then((inst) {
|
||||
if (inst.containsKey('post_editor_local_save')) {
|
||||
isRestoreFromLocal.value = true;
|
||||
payload = jsonDecode(inst.getString('post_editor_local_save')!);
|
||||
}
|
||||
});
|
||||
Future<bool> localRead() async {
|
||||
final inst = await SharedPreferences.getInstance();
|
||||
if (inst.containsKey('post_editor_local_save')) {
|
||||
isRestoreFromLocal.value = true;
|
||||
payload = jsonDecode(inst.getString('post_editor_local_save')!);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void localClear() {
|
||||
@ -168,6 +186,7 @@ class PostEditorController extends GetxController {
|
||||
}
|
||||
|
||||
void currentClear() {
|
||||
aliasController.clear();
|
||||
titleController.clear();
|
||||
descriptionController.clear();
|
||||
contentController.clear();
|
||||
@ -197,16 +216,23 @@ class PostEditorController extends GetxController {
|
||||
|
||||
type = value.type;
|
||||
editTo.value = value;
|
||||
realmZone.value = value.realm;
|
||||
isDraft.value = value.isDraft ?? false;
|
||||
aliasController.text = value.alias ?? '';
|
||||
titleController.text = value.body['title'] ?? '';
|
||||
descriptionController.text = value.body['description'] ?? '';
|
||||
contentController.text = value.body['content'] ?? '';
|
||||
publishedAt.value = value.publishedAt;
|
||||
publishedUntil.value = value.publishedUntil;
|
||||
tags.value =
|
||||
value.body['tags']?.map((x) => x['alias']).toList() ?? List.empty();
|
||||
tags.value = List.from(
|
||||
value.body['tags']?.map((x) => x['alias']).toList() ?? List.empty(),
|
||||
growable: true,
|
||||
);
|
||||
tags.refresh();
|
||||
attachments.value = value.body['attachments']?.cast<int>() ?? List.empty();
|
||||
attachments.value = List.from(
|
||||
value.body['attachments'] ?? List.empty(),
|
||||
growable: true,
|
||||
);
|
||||
attachments.refresh();
|
||||
thumbnail.value = value.body['thumbnail'];
|
||||
|
||||
@ -256,6 +282,7 @@ class PostEditorController extends GetxController {
|
||||
|
||||
Map<String, dynamic> get payload {
|
||||
return {
|
||||
'alias': aliasController.text,
|
||||
'title': title,
|
||||
'description': description,
|
||||
'content': contentController.text,
|
||||
@ -277,20 +304,33 @@ class PostEditorController extends GetxController {
|
||||
|
||||
set payload(Map<String, dynamic> value) {
|
||||
type = value['type'];
|
||||
tags.value = value['tags'].map((x) => x['alias']).toList().cast<String>();
|
||||
tags.value = List.from(
|
||||
value['tags'].map((x) => x['alias']).toList(),
|
||||
growable: true,
|
||||
);
|
||||
aliasController.text = value['alias'] ?? '';
|
||||
titleController.text = value['title'] ?? '';
|
||||
descriptionController.text = value['description'] ?? '';
|
||||
contentController.text = value['content'] ?? '';
|
||||
attachments.value = value['attachments'].cast<int>() ?? List.empty();
|
||||
attachments.value = List.from(
|
||||
value['attachments'] ?? List.empty(),
|
||||
growable: true,
|
||||
);
|
||||
attachments.refresh();
|
||||
thumbnail.value = value['thumbnail'];
|
||||
visibility.value = value['visibility'];
|
||||
isDraft.value = value['is_draft'];
|
||||
if (value['visible_users'] != null) {
|
||||
visibleUsers.value = value['visible_users'].cast<int>();
|
||||
visibleUsers.value = List.from(
|
||||
value['visible_users'],
|
||||
growable: true,
|
||||
);
|
||||
}
|
||||
if (value['invisible_users'] != null) {
|
||||
invisibleUsers.value = value['invisible_users'].cast<int>();
|
||||
invisibleUsers.value = List.from(
|
||||
value['invisible_users'],
|
||||
growable: true,
|
||||
);
|
||||
}
|
||||
if (value['published_at'] != null) {
|
||||
publishedAt.value = DateTime.parse(value['published_at']).toLocal();
|
||||
@ -319,6 +359,7 @@ class PostEditorController extends GetxController {
|
||||
|
||||
bool get isNotEmpty {
|
||||
return [
|
||||
aliasController.text.isNotEmpty,
|
||||
titleController.text.isNotEmpty,
|
||||
descriptionController.text.isNotEmpty,
|
||||
contentController.text.isNotEmpty,
|
||||
@ -330,8 +371,6 @@ class PostEditorController extends GetxController {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_saveTimer?.cancel();
|
||||
|
||||
titleController.dispose();
|
||||
descriptionController.dispose();
|
||||
contentController.dispose();
|
||||
|
@ -1,19 +1,27 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
import 'package:solian/models/attachment.dart';
|
||||
import 'package:solian/models/pagination.dart';
|
||||
import 'package:solian/models/post.dart';
|
||||
import 'package:solian/providers/content/attachment.dart';
|
||||
import 'package:solian/providers/content/posts.dart';
|
||||
import 'package:solian/providers/last_read.dart';
|
||||
|
||||
class PostListController extends GetxController {
|
||||
String? author;
|
||||
String? realm;
|
||||
|
||||
/// The polling source modifier.
|
||||
/// - `0`: default recommendations
|
||||
/// - `1`: shuffle mode
|
||||
/// - `1`: friend mode
|
||||
/// - `2`: shuffle mode
|
||||
RxInt mode = 0.obs;
|
||||
|
||||
/// The paging controller for infinite loading.
|
||||
/// Only available when mode is `0`.
|
||||
/// Only available when mode is `0`, `1` or `2`.
|
||||
PagingController<int, Post> pagingController =
|
||||
PagingController(firstPageKey: 0);
|
||||
|
||||
@ -26,9 +34,18 @@ class PostListController extends GetxController {
|
||||
pagingController.addPageRequestListener(_onPagingControllerRequest);
|
||||
}
|
||||
|
||||
Completer<void>? _pagingLoadCompleter;
|
||||
|
||||
Future<void> _onPagingControllerRequest(int pageKey) async {
|
||||
try {
|
||||
if (_pagingLoadCompleter != null) {
|
||||
await _pagingLoadCompleter!.future;
|
||||
return;
|
||||
}
|
||||
_pagingLoadCompleter = Completer();
|
||||
final result = await loadMore();
|
||||
_pagingLoadCompleter!.complete();
|
||||
_pagingLoadCompleter = null;
|
||||
|
||||
if (result != null && hasMore.value) {
|
||||
pagingController.appendPage(result, nextPageKey.value);
|
||||
@ -92,8 +109,10 @@ class PostListController extends GetxController {
|
||||
hasMore.value = false;
|
||||
}
|
||||
|
||||
final idx = <dynamic>{};
|
||||
postList.retainWhere((x) => idx.add(x.id));
|
||||
if (postList.isNotEmpty) {
|
||||
var lastId = postList.map((x) => x.id).reduce(max);
|
||||
Get.find<LastReadProvider>().feedLastReadAt = lastId;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -101,20 +120,42 @@ class PostListController extends GetxController {
|
||||
Future<List<Post>?> _loadPosts(int pageKey) async {
|
||||
isBusy.value = true;
|
||||
|
||||
final PostProvider provider = Get.find();
|
||||
final PostProvider posts = Get.find();
|
||||
|
||||
Response resp;
|
||||
try {
|
||||
if (author != null) {
|
||||
resp = await provider.listPost(
|
||||
resp = await posts.listPost(
|
||||
pageKey,
|
||||
author: author,
|
||||
take: 10,
|
||||
);
|
||||
} else {
|
||||
resp = await provider.listRecommendations(
|
||||
pageKey,
|
||||
channel: mode.value == 0 ? null : 'shuffle',
|
||||
);
|
||||
switch (mode.value) {
|
||||
case 2:
|
||||
resp = await posts.listRecommendations(
|
||||
pageKey,
|
||||
channel: 'shuffle',
|
||||
realm: realm,
|
||||
take: 10,
|
||||
);
|
||||
break;
|
||||
case 1:
|
||||
resp = await posts.listRecommendations(
|
||||
pageKey,
|
||||
channel: 'friends',
|
||||
realm: realm,
|
||||
take: 10,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
resp = await posts.listRecommendations(
|
||||
pageKey,
|
||||
realm: realm,
|
||||
take: 10,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
@ -125,6 +166,27 @@ class PostListController extends GetxController {
|
||||
final result = PaginationResult.fromJson(resp.body);
|
||||
final out = result.data?.map((e) => Post.fromJson(e)).toList();
|
||||
|
||||
final AttachmentProvider attach = Get.find();
|
||||
|
||||
if (out != null) {
|
||||
final attachmentIds = out
|
||||
.mapMany((x) => x.body['attachments'] ?? [])
|
||||
.cast<String>()
|
||||
.toSet()
|
||||
.toList();
|
||||
final attachmentOut = await attach.listMetadata(attachmentIds);
|
||||
|
||||
for (var idx = 0; idx < out.length; idx++) {
|
||||
final rids = List<String>.from(out[idx].body['attachments'] ?? []);
|
||||
out[idx].preload = PostPreload(
|
||||
attachments: attachmentOut
|
||||
.where((x) => x != null && rids.contains(x.rid))
|
||||
.cast<Attachment>()
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
postTotal.value = result.count;
|
||||
|
||||
return out;
|
||||
|
10
lib/exceptions/request.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class RequestException implements Exception {
|
||||
final Response data;
|
||||
|
||||
const RequestException(this.data);
|
||||
|
||||
@override
|
||||
String toString() => 'Request failed ${data.statusCode}: ${data.bodyString}';
|
||||
}
|
6
lib/exceptions/unauthorized.dart
Normal file
@ -0,0 +1,6 @@
|
||||
class UnauthorizedException implements Exception {
|
||||
const UnauthorizedException();
|
||||
|
||||
@override
|
||||
String toString() => 'Unauthorized';
|
||||
}
|
135
lib/exts.dart
@ -1,7 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
extension SolianExtenions on BuildContext {
|
||||
import 'package:action_slider/action_slider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:solian/exceptions/request.dart';
|
||||
import 'package:solian/exceptions/unauthorized.dart';
|
||||
|
||||
extension AppExtensions on BuildContext {
|
||||
void showSnackbar(String content, {SnackBarAction? action}) {
|
||||
ScaffoldMessenger.of(this).showSnackBar(SnackBar(
|
||||
content: Text(content),
|
||||
@ -47,16 +53,112 @@ extension SolianExtenions on BuildContext {
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> showConfirmDialog(String title, body) async {
|
||||
return await showDialog<bool>(
|
||||
useRootNavigator: true,
|
||||
context: this,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(title),
|
||||
content: Text(body),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, false),
|
||||
child: Text('cancel'.tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: Text('okay'.tr),
|
||||
)
|
||||
],
|
||||
),
|
||||
) ??
|
||||
false;
|
||||
}
|
||||
|
||||
Future<bool> showSlideToConfirmDialog(String title, body) async {
|
||||
return await showDialog<bool>(
|
||||
useRootNavigator: true,
|
||||
context: this,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(title, textAlign: TextAlign.center),
|
||||
content: SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
Text(body, textAlign: TextAlign.center),
|
||||
const Gap(28),
|
||||
ActionSlider.standard(
|
||||
icon: const Icon(Icons.send),
|
||||
iconAlignment: Alignment.center,
|
||||
sliderBehavior: SliderBehavior.move,
|
||||
actionThresholdType: ThresholdType.release,
|
||||
toggleColor: Colors.red,
|
||||
action: (controller) async {
|
||||
controller.success();
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
Navigator.pop(ctx, true);
|
||||
},
|
||||
child: Text('slideToConfirm'.tr),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actionsAlignment: MainAxisAlignment.center,
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, false),
|
||||
child: Text('cancel'.tr),
|
||||
)
|
||||
],
|
||||
),
|
||||
) ??
|
||||
false;
|
||||
}
|
||||
|
||||
Future<void> showErrorDialog(dynamic exception) {
|
||||
var stack = StackTrace.current;
|
||||
var stackTrace = '$stack';
|
||||
Widget content = Text(exception.toString().capitalize!);
|
||||
if (exception is UnauthorizedException) {
|
||||
content = Text('errorHappenedUnauthorized'.tr);
|
||||
}
|
||||
if (exception is RequestException) {
|
||||
String overall;
|
||||
switch (exception.data.statusCode) {
|
||||
case 400:
|
||||
overall = 'errorHappenedRequestBad'.tr;
|
||||
break;
|
||||
case 401:
|
||||
overall = 'errorHappenedUnauthorized'.tr;
|
||||
break;
|
||||
case 403:
|
||||
overall = 'errorHappenedRequestForbidden'.tr;
|
||||
break;
|
||||
case 404:
|
||||
overall = 'errorHappenedRequestNotFound'.tr;
|
||||
break;
|
||||
case null:
|
||||
overall = 'errorHappenedRequestConnection'.tr;
|
||||
break;
|
||||
default:
|
||||
overall = 'errorHappenedRequestUnknown'.tr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (exception.data.statusCode != null) {
|
||||
content = Text(
|
||||
'$overall\n\n(${exception.data.statusCode}) ${exception.data.bodyString}',
|
||||
);
|
||||
} else {
|
||||
content = Text(overall);
|
||||
}
|
||||
}
|
||||
|
||||
return showDialog<void>(
|
||||
useRootNavigator: true,
|
||||
context: this,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text('errorHappened'.tr),
|
||||
content: Text('${exception.toString().capitalize!}\n\nStack Trace: $stackTrace'),
|
||||
content: content,
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
@ -67,3 +169,24 @@ extension SolianExtenions on BuildContext {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension ByteFormatter on int {
|
||||
String formatBytes({int decimals = 2}) {
|
||||
if (this == 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
final dm = decimals < 0 ? 0 : decimals;
|
||||
final sizes = [
|
||||
'Bytes',
|
||||
'KiB',
|
||||
'MiB',
|
||||
'GiB',
|
||||
'TiB',
|
||||
'PiB',
|
||||
'EiB',
|
||||
'ZiB',
|
||||
'YiB'
|
||||
];
|
||||
final i = (math.log(this) / math.log(k)).floor().toInt();
|
||||
return '${(this / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,25 @@ import 'dart:ui';
|
||||
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart' hide Notification;
|
||||
import 'package:flutter_acrylic/flutter_acrylic.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:protocol_handler/protocol_handler.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:solian/bootstrapper.dart';
|
||||
import 'package:solian/background.dart';
|
||||
import 'package:solian/firebase_options.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
import 'package:solian/providers/attachment_uploader.dart';
|
||||
import 'package:solian/providers/daily_sign.dart';
|
||||
import 'package:solian/providers/database/database.dart';
|
||||
import 'package:solian/providers/database/services/messages.dart';
|
||||
import 'package:solian/providers/last_read.dart';
|
||||
import 'package:solian/providers/link_expander.dart';
|
||||
import 'package:solian/providers/navigation.dart';
|
||||
import 'package:solian/providers/notifications.dart';
|
||||
import 'package:solian/providers/stickers.dart';
|
||||
import 'package:solian/providers/subscription.dart';
|
||||
import 'package:solian/providers/theme_switcher.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
@ -32,28 +39,40 @@ import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy;
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
await Future.wait([
|
||||
_initializeFirebase(),
|
||||
_initializePlatformComponents(),
|
||||
_initializeBackgroundNotificationService(),
|
||||
]);
|
||||
|
||||
GoRouter.optionURLReflectsImperativeAPIs = true;
|
||||
|
||||
Get.put(DatabaseProvider());
|
||||
Get.put(AppTranslations());
|
||||
await AppTranslations.init();
|
||||
|
||||
usePathUrlStrategy();
|
||||
runApp(const SolianApp());
|
||||
}
|
||||
|
||||
Future<void> _initializeFirebase() async {
|
||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||
FlutterError.onError = (errorDetails) {
|
||||
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
|
||||
};
|
||||
PlatformDispatcher.instance.onError = (error, stack) {
|
||||
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
|
||||
return true;
|
||||
};
|
||||
if (PlatformInfo.isIOS || PlatformInfo.isAndroid || PlatformInfo.isMacOS) {
|
||||
// Initialize firebase crashlytics for the platform that supported
|
||||
FlutterError.onError = (errorDetails) {
|
||||
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
|
||||
};
|
||||
PlatformDispatcher.instance.onError = (error, stack) {
|
||||
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initializeBackgroundNotificationService() async {
|
||||
autoConfigureBackgroundNotificationService();
|
||||
autoStartBackgroundNotificationService();
|
||||
}
|
||||
|
||||
Future<void> _initializePlatformComponents() async {
|
||||
@ -75,8 +94,8 @@ Future<void> _initializePlatformComponents() async {
|
||||
}
|
||||
|
||||
final themeSwitcher = ThemeSwitcher(
|
||||
lightThemeData: SolianTheme.build(Brightness.light),
|
||||
darkThemeData: SolianTheme.build(Brightness.dark),
|
||||
lightThemeData: AppTheme.build(Brightness.light),
|
||||
darkThemeData: AppTheme.build(Brightness.dark),
|
||||
);
|
||||
|
||||
class SolianApp extends StatelessWidget {
|
||||
@ -98,16 +117,16 @@ class SolianApp extends StatelessWidget {
|
||||
routeInformationParser: AppRouter.instance.routeInformationParser,
|
||||
routeInformationProvider: AppRouter.instance.routeInformationProvider,
|
||||
backButtonDispatcher: AppRouter.instance.backButtonDispatcher,
|
||||
translations: SolianMessages(),
|
||||
translations: Get.find<AppTranslations>(),
|
||||
locale: Get.deviceLocale,
|
||||
fallbackLocale: const Locale('en', 'US'),
|
||||
onInit: () => _initializeProviders(context),
|
||||
onInit: () {
|
||||
_initializeProviders(context);
|
||||
},
|
||||
builder: (context, child) {
|
||||
return SystemShell(
|
||||
child: ScaffoldMessenger(
|
||||
child: BootstrapperShell(
|
||||
child: child ?? const SizedBox(),
|
||||
),
|
||||
child: child ?? const SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -117,16 +136,26 @@ class SolianApp extends StatelessWidget {
|
||||
}
|
||||
|
||||
void _initializeProviders(BuildContext context) async {
|
||||
Get.put(NavigationStateProvider());
|
||||
|
||||
Get.lazyPut(() => AuthProvider());
|
||||
Get.lazyPut(() => WebSocketProvider());
|
||||
Get.lazyPut(() => RelationshipProvider());
|
||||
Get.lazyPut(() => PostProvider());
|
||||
Get.lazyPut(() => StickerProvider());
|
||||
Get.lazyPut(() => AttachmentProvider());
|
||||
Get.lazyPut(() => WebSocketProvider());
|
||||
Get.lazyPut(() => NotificationProvider());
|
||||
Get.lazyPut(() => StatusProvider());
|
||||
Get.lazyPut(() => ChannelProvider());
|
||||
Get.lazyPut(() => RealmProvider());
|
||||
Get.lazyPut(() => MessagesFetchingProvider());
|
||||
Get.lazyPut(() => ChatCallProvider());
|
||||
Get.lazyPut(() => AttachmentUploaderController());
|
||||
Get.lazyPut(() => LinkExpandProvider());
|
||||
Get.lazyPut(() => DailySignProvider());
|
||||
Get.lazyPut(() => LastReadProvider());
|
||||
Get.lazyPut(() => SubscriptionProvider());
|
||||
|
||||
Get.find<NotificationProvider>().requestPermissions();
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'account.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Account {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
@ -10,9 +15,9 @@ class Account {
|
||||
dynamic avatar;
|
||||
dynamic banner;
|
||||
String description;
|
||||
AccountProfile? profile;
|
||||
List<AccountBadge>? badges;
|
||||
String? emailAddress;
|
||||
int? externalId;
|
||||
|
||||
Account({
|
||||
required this.id,
|
||||
@ -26,55 +31,18 @@ class Account {
|
||||
required this.avatar,
|
||||
required this.banner,
|
||||
required this.description,
|
||||
required this.profile,
|
||||
required this.badges,
|
||||
required this.emailAddress,
|
||||
this.externalId,
|
||||
});
|
||||
|
||||
factory Account.fromJson(Map<String, dynamic> json) => Account(
|
||||
id: json['id'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'] != null
|
||||
? DateTime.parse(json['deleted_at'])
|
||||
: null,
|
||||
confirmedAt: json['confirmed_at'] != null
|
||||
? DateTime.parse(json['confirmed_at'])
|
||||
: null,
|
||||
suspendedAt: json['suspended_at'] != null
|
||||
? DateTime.parse(json['suspended_at'])
|
||||
: null,
|
||||
name: json['name'],
|
||||
nick: json['nick'],
|
||||
avatar: json['avatar'],
|
||||
banner: json['banner'],
|
||||
description: json['description'],
|
||||
emailAddress: json['email_address'],
|
||||
badges: json['badges']
|
||||
?.map((e) => AccountBadge.fromJson(e))
|
||||
.toList()
|
||||
.cast<AccountBadge>(),
|
||||
externalId: json['external_id'],
|
||||
);
|
||||
factory Account.fromJson(Map<String, dynamic> json) =>
|
||||
_$AccountFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt?.toIso8601String(),
|
||||
'confirmed_at': confirmedAt?.toIso8601String(),
|
||||
'suspended_at': suspendedAt?.toIso8601String(),
|
||||
'name': name,
|
||||
'nick': nick,
|
||||
'avatar': avatar,
|
||||
'banner': banner,
|
||||
'description': description,
|
||||
'email_address': emailAddress,
|
||||
'badges': badges?.map((e) => e.toJson()).toList(),
|
||||
'external_id': externalId,
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$AccountToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class AccountBadge {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
@ -94,25 +62,40 @@ class AccountBadge {
|
||||
required this.type,
|
||||
});
|
||||
|
||||
factory AccountBadge.fromJson(Map<String, dynamic> json) => AccountBadge(
|
||||
id: json['id'],
|
||||
accountId: json['account_id'],
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
deletedAt: json['deleted_at'] != null
|
||||
? DateTime.parse(json['deleted_at'])
|
||||
: null,
|
||||
metadata: json['metadata'],
|
||||
type: json['type'],
|
||||
);
|
||||
factory AccountBadge.fromJson(Map<String, dynamic> json) =>
|
||||
_$AccountBadgeFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'account_id': accountId,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt?.toIso8601String(),
|
||||
'metadata': metadata,
|
||||
'type': type,
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$AccountBadgeToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class AccountProfile {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
String? firstName;
|
||||
String? lastName;
|
||||
int? experience;
|
||||
DateTime? lastSeenAt;
|
||||
DateTime? birthday;
|
||||
int accountId;
|
||||
|
||||
AccountProfile({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
required this.experience,
|
||||
required this.lastSeenAt,
|
||||
required this.birthday,
|
||||
required this.accountId,
|
||||
});
|
||||
|
||||
factory AccountProfile.fromJson(Map<String, dynamic> json) =>
|
||||
_$AccountProfileFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AccountProfileToJson(this);
|
||||
}
|
||||
|
108
lib/models/account.g.dart
Normal file
@ -0,0 +1,108 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'account.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Account _$AccountFromJson(Map<String, dynamic> json) => Account(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
confirmedAt: json['confirmed_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['confirmed_at'] as String),
|
||||
suspendedAt: json['suspended_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['suspended_at'] as String),
|
||||
name: json['name'] as String,
|
||||
nick: json['nick'] as String,
|
||||
avatar: json['avatar'],
|
||||
banner: json['banner'],
|
||||
description: json['description'] as String,
|
||||
profile: json['profile'] == null
|
||||
? null
|
||||
: AccountProfile.fromJson(json['profile'] as Map<String, dynamic>),
|
||||
badges: (json['badges'] as List<dynamic>?)
|
||||
?.map((e) => AccountBadge.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
emailAddress: json['email_address'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AccountToJson(Account instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'confirmed_at': instance.confirmedAt?.toIso8601String(),
|
||||
'suspended_at': instance.suspendedAt?.toIso8601String(),
|
||||
'name': instance.name,
|
||||
'nick': instance.nick,
|
||||
'avatar': instance.avatar,
|
||||
'banner': instance.banner,
|
||||
'description': instance.description,
|
||||
'profile': instance.profile?.toJson(),
|
||||
'badges': instance.badges?.map((e) => e.toJson()).toList(),
|
||||
'email_address': instance.emailAddress,
|
||||
};
|
||||
|
||||
AccountBadge _$AccountBadgeFromJson(Map<String, dynamic> json) => AccountBadge(
|
||||
id: (json['id'] as num).toInt(),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||
type: json['type'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AccountBadgeToJson(AccountBadge instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'metadata': instance.metadata,
|
||||
'type': instance.type,
|
||||
'account_id': instance.accountId,
|
||||
};
|
||||
|
||||
AccountProfile _$AccountProfileFromJson(Map<String, dynamic> json) =>
|
||||
AccountProfile(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
firstName: json['first_name'] as String?,
|
||||
lastName: json['last_name'] as String?,
|
||||
experience: (json['experience'] as num?)?.toInt(),
|
||||
lastSeenAt: json['last_seen_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_seen_at'] as String),
|
||||
birthday: json['birthday'] == null
|
||||
? null
|
||||
: DateTime.parse(json['birthday'] as String),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AccountProfileToJson(AccountProfile instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'first_name': instance.firstName,
|
||||
'last_name': instance.lastName,
|
||||
'experience': instance.experience,
|
||||
'last_seen_at': instance.lastSeenAt?.toIso8601String(),
|
||||
'birthday': instance.birthday?.toIso8601String(),
|
||||
'account_id': instance.accountId,
|
||||
};
|
@ -1,3 +1,8 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'account_status.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AccountStatus {
|
||||
bool isDisturbable;
|
||||
bool isOnline;
|
||||
@ -11,21 +16,13 @@ class AccountStatus {
|
||||
required this.status,
|
||||
});
|
||||
|
||||
factory AccountStatus.fromJson(Map<String, dynamic> json) => AccountStatus(
|
||||
isDisturbable: json['is_disturbable'],
|
||||
isOnline: json['is_online'],
|
||||
lastSeenAt: json['last_seen_at'] != null ? DateTime.parse(json['last_seen_at']) : null,
|
||||
status: json['status'] != null ? Status.fromJson(json['status']) : null,
|
||||
);
|
||||
factory AccountStatus.fromJson(Map<String, dynamic> json) =>
|
||||
_$AccountStatusFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'is_disturbable': isDisturbable,
|
||||
'is_online': isOnline,
|
||||
'last_seen_at': lastSeenAt?.toIso8601String(),
|
||||
'status': status?.toJson(),
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$AccountStatusToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class Status {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
@ -53,31 +50,7 @@ class Status {
|
||||
required this.accountId,
|
||||
});
|
||||
|
||||
factory Status.fromJson(Map<String, dynamic> json) => Status(
|
||||
id: json['id'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'] != null ? DateTime.parse(json['deleted_at']) : null,
|
||||
type: json['type'],
|
||||
label: json['label'],
|
||||
attitude: json['attitude'],
|
||||
isNoDisturb: json['is_no_disturb'],
|
||||
isInvisible: json['is_invisible'],
|
||||
clearAt: json['clear_at'] != null ? DateTime.parse(json['clear_at']) : null,
|
||||
accountId: json['account_id'],
|
||||
);
|
||||
factory Status.fromJson(Map<String, dynamic> json) => _$StatusFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt?.toIso8601String(),
|
||||
'type': type,
|
||||
'label': label,
|
||||
'attitude': attitude,
|
||||
'is_no_disturb': isNoDisturb,
|
||||
'is_invisible': isInvisible,
|
||||
'clear_at': clearAt?.toIso8601String(),
|
||||
'account_id': accountId,
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$StatusToJson(this);
|
||||
}
|
||||
|
59
lib/models/account_status.g.dart
Normal file
@ -0,0 +1,59 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'account_status.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
AccountStatus _$AccountStatusFromJson(Map<String, dynamic> json) =>
|
||||
AccountStatus(
|
||||
isDisturbable: json['is_disturbable'] as bool,
|
||||
isOnline: json['is_online'] as bool,
|
||||
lastSeenAt: json['last_seen_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_seen_at'] as String),
|
||||
status: json['status'] == null
|
||||
? null
|
||||
: Status.fromJson(json['status'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AccountStatusToJson(AccountStatus instance) =>
|
||||
<String, dynamic>{
|
||||
'is_disturbable': instance.isDisturbable,
|
||||
'is_online': instance.isOnline,
|
||||
'last_seen_at': instance.lastSeenAt?.toIso8601String(),
|
||||
'status': instance.status?.toJson(),
|
||||
};
|
||||
|
||||
Status _$StatusFromJson(Map<String, dynamic> json) => Status(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
type: json['type'] as String,
|
||||
label: json['label'] as String,
|
||||
attitude: (json['attitude'] as num).toInt(),
|
||||
isNoDisturb: json['is_no_disturb'] as bool,
|
||||
isInvisible: json['is_invisible'] as bool,
|
||||
clearAt: json['clear_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['clear_at'] as String),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$StatusToJson(Status instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'type': instance.type,
|
||||
'label': instance.label,
|
||||
'attitude': instance.attitude,
|
||||
'is_no_disturb': instance.isNoDisturb,
|
||||
'is_invisible': instance.isInvisible,
|
||||
'clear_at': instance.clearAt?.toIso8601String(),
|
||||
'account_id': instance.accountId,
|
||||
};
|
@ -1,20 +1,44 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
|
||||
part 'attachment.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AttachmentPlaceholder {
|
||||
int chunkCount;
|
||||
int chunkSize;
|
||||
Attachment meta;
|
||||
|
||||
AttachmentPlaceholder({
|
||||
required this.chunkCount,
|
||||
required this.chunkSize,
|
||||
required this.meta,
|
||||
});
|
||||
|
||||
factory AttachmentPlaceholder.fromJson(Map<String, dynamic> json) =>
|
||||
_$AttachmentPlaceholderFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AttachmentPlaceholderToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class Attachment {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
String rid;
|
||||
String uuid;
|
||||
int size;
|
||||
String name;
|
||||
String alt;
|
||||
String usage;
|
||||
String mimetype;
|
||||
String hash;
|
||||
int destination;
|
||||
bool isAnalyzed;
|
||||
bool isUploaded;
|
||||
Map<String, dynamic>? metadata;
|
||||
Map<String, dynamic>? fileChunks;
|
||||
bool isMature;
|
||||
Account? account;
|
||||
int? accountId;
|
||||
@ -24,58 +48,25 @@ class Attachment {
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.rid,
|
||||
required this.uuid,
|
||||
required this.size,
|
||||
required this.name,
|
||||
required this.alt,
|
||||
required this.usage,
|
||||
required this.mimetype,
|
||||
required this.hash,
|
||||
required this.destination,
|
||||
required this.isAnalyzed,
|
||||
required this.isUploaded,
|
||||
required this.metadata,
|
||||
required this.fileChunks,
|
||||
required this.isMature,
|
||||
required this.account,
|
||||
required this.accountId,
|
||||
});
|
||||
|
||||
factory Attachment.fromJson(Map<String, dynamic> json) => Attachment(
|
||||
id: json['id'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'] != null ? DateTime.parse(json['deleted_at']) : null,
|
||||
uuid: json['uuid'],
|
||||
size: json['size'],
|
||||
name: json['name'],
|
||||
alt: json['alt'],
|
||||
usage: json['usage'],
|
||||
mimetype: json['mimetype'],
|
||||
hash: json['hash'],
|
||||
destination: json['destination'],
|
||||
isAnalyzed: json['is_analyzed'],
|
||||
metadata: json['metadata'],
|
||||
isMature: json['is_mature'],
|
||||
account: json['account'] != null ? Account.fromJson(json['account']) : null,
|
||||
accountId: json['account_id'],
|
||||
);
|
||||
factory Attachment.fromJson(Map<String, dynamic> json) =>
|
||||
_$AttachmentFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt?.toIso8601String(),
|
||||
'uuid': uuid,
|
||||
'size': size,
|
||||
'name': name,
|
||||
'alt': alt,
|
||||
'usage': usage,
|
||||
'mimetype': mimetype,
|
||||
'hash': hash,
|
||||
'destination': destination,
|
||||
'is_analyzed': isAnalyzed,
|
||||
'metadata': metadata,
|
||||
'is_mature': isMature,
|
||||
'account': account?.toJson(),
|
||||
'account_id': accountId,
|
||||
};
|
||||
}
|
||||
Map<String, dynamic> toJson() => _$AttachmentToJson(this);
|
||||
}
|
||||
|
72
lib/models/attachment.g.dart
Normal file
@ -0,0 +1,72 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'attachment.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
AttachmentPlaceholder _$AttachmentPlaceholderFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
AttachmentPlaceholder(
|
||||
chunkCount: (json['chunk_count'] as num).toInt(),
|
||||
chunkSize: (json['chunk_size'] as num).toInt(),
|
||||
meta: Attachment.fromJson(json['meta'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AttachmentPlaceholderToJson(
|
||||
AttachmentPlaceholder instance) =>
|
||||
<String, dynamic>{
|
||||
'chunk_count': instance.chunkCount,
|
||||
'chunk_size': instance.chunkSize,
|
||||
'meta': instance.meta.toJson(),
|
||||
};
|
||||
|
||||
Attachment _$AttachmentFromJson(Map<String, dynamic> json) => Attachment(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
rid: json['rid'] as String,
|
||||
uuid: json['uuid'] as String,
|
||||
size: (json['size'] as num).toInt(),
|
||||
name: json['name'] as String,
|
||||
alt: json['alt'] as String,
|
||||
mimetype: json['mimetype'] as String,
|
||||
hash: json['hash'] as String,
|
||||
destination: (json['destination'] as num).toInt(),
|
||||
isAnalyzed: json['is_analyzed'] as bool,
|
||||
isUploaded: json['is_uploaded'] as bool,
|
||||
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||
fileChunks: json['file_chunks'] as Map<String, dynamic>?,
|
||||
isMature: json['is_mature'] as bool,
|
||||
account: json['account'] == null
|
||||
? null
|
||||
: Account.fromJson(json['account'] as Map<String, dynamic>),
|
||||
accountId: (json['account_id'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AttachmentToJson(Attachment instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'rid': instance.rid,
|
||||
'uuid': instance.uuid,
|
||||
'size': instance.size,
|
||||
'name': instance.name,
|
||||
'alt': instance.alt,
|
||||
'mimetype': instance.mimetype,
|
||||
'hash': instance.hash,
|
||||
'destination': instance.destination,
|
||||
'is_analyzed': instance.isAnalyzed,
|
||||
'is_uploaded': instance.isUploaded,
|
||||
'metadata': instance.metadata,
|
||||
'file_chunks': instance.fileChunks,
|
||||
'is_mature': instance.isMature,
|
||||
'account': instance.account?.toJson(),
|
||||
'account_id': instance.accountId,
|
||||
};
|
38
lib/models/audit_log.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
|
||||
part 'audit_log.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AuditEvent {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
String type;
|
||||
String target;
|
||||
String location;
|
||||
String ipAddress;
|
||||
String userAgent;
|
||||
Account account;
|
||||
int accountId;
|
||||
|
||||
AuditEvent({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.type,
|
||||
required this.target,
|
||||
required this.location,
|
||||
required this.ipAddress,
|
||||
required this.userAgent,
|
||||
required this.account,
|
||||
required this.accountId,
|
||||
});
|
||||
|
||||
static AuditEvent fromJson(Map<String, dynamic> json) =>
|
||||
_$AuditEventFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AuditEventToJson(this);
|
||||
}
|
38
lib/models/audit_log.g.dart
Normal file
@ -0,0 +1,38 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'audit_log.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
AuditEvent _$AuditEventFromJson(Map<String, dynamic> json) => AuditEvent(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
type: json['type'] as String,
|
||||
target: json['target'] as String,
|
||||
location: json['location'] as String,
|
||||
ipAddress: json['ip_address'] as String,
|
||||
userAgent: json['user_agent'] as String,
|
||||
account: Account.fromJson(json['account'] as Map<String, dynamic>),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AuditEventToJson(AuditEvent instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'type': instance.type,
|
||||
'target': instance.target,
|
||||
'location': instance.location,
|
||||
'ip_address': instance.ipAddress,
|
||||
'user_agent': instance.userAgent,
|
||||
'account': instance.account.toJson(),
|
||||
'account_id': instance.accountId,
|
||||
};
|
103
lib/models/auth.dart
Normal file
@ -0,0 +1,103 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
|
||||
part 'auth.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AuthResult {
|
||||
bool isFinished;
|
||||
AuthTicket ticket;
|
||||
|
||||
AuthResult({
|
||||
required this.isFinished,
|
||||
required this.ticket,
|
||||
});
|
||||
|
||||
factory AuthResult.fromJson(Map<String, dynamic> json) =>
|
||||
_$AuthResultFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AuthResultToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class AuthTicket {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
String location;
|
||||
String ipAddress;
|
||||
String userAgent;
|
||||
int stepRemain;
|
||||
List<String> claims;
|
||||
List<String> audiences;
|
||||
@JsonKey(defaultValue: [])
|
||||
List<int> factorTrail;
|
||||
String? grantToken;
|
||||
String? accessToken;
|
||||
String? refreshToken;
|
||||
DateTime? expiredAt;
|
||||
DateTime? availableAt;
|
||||
DateTime? lastGrantAt;
|
||||
String? nonce;
|
||||
int? clientId;
|
||||
Account account;
|
||||
int accountId;
|
||||
|
||||
AuthTicket({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.location,
|
||||
required this.ipAddress,
|
||||
required this.userAgent,
|
||||
required this.stepRemain,
|
||||
required this.claims,
|
||||
required this.audiences,
|
||||
required this.factorTrail,
|
||||
required this.grantToken,
|
||||
required this.accessToken,
|
||||
required this.refreshToken,
|
||||
required this.expiredAt,
|
||||
required this.availableAt,
|
||||
required this.lastGrantAt,
|
||||
required this.nonce,
|
||||
required this.clientId,
|
||||
required this.account,
|
||||
required this.accountId,
|
||||
});
|
||||
|
||||
factory AuthTicket.fromJson(Map<String, dynamic> json) =>
|
||||
_$AuthTicketFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AuthTicketToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class AuthFactor {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
int type;
|
||||
Map<String, dynamic>? config;
|
||||
Account account;
|
||||
int accountId;
|
||||
|
||||
AuthFactor({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.type,
|
||||
required this.config,
|
||||
required this.account,
|
||||
required this.accountId,
|
||||
});
|
||||
|
||||
factory AuthFactor.fromJson(Map<String, dynamic> json) =>
|
||||
_$AuthFactorFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AuthFactorToJson(this);
|
||||
}
|
105
lib/models/auth.g.dart
Normal file
@ -0,0 +1,105 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'auth.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
AuthResult _$AuthResultFromJson(Map<String, dynamic> json) => AuthResult(
|
||||
isFinished: json['is_finished'] as bool,
|
||||
ticket: AuthTicket.fromJson(json['ticket'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AuthResultToJson(AuthResult instance) =>
|
||||
<String, dynamic>{
|
||||
'is_finished': instance.isFinished,
|
||||
'ticket': instance.ticket.toJson(),
|
||||
};
|
||||
|
||||
AuthTicket _$AuthTicketFromJson(Map<String, dynamic> json) => AuthTicket(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
location: json['location'] as String,
|
||||
ipAddress: json['ip_address'] as String,
|
||||
userAgent: json['user_agent'] as String,
|
||||
stepRemain: (json['step_remain'] as num).toInt(),
|
||||
claims:
|
||||
(json['claims'] as List<dynamic>).map((e) => e as String).toList(),
|
||||
audiences:
|
||||
(json['audiences'] as List<dynamic>).map((e) => e as String).toList(),
|
||||
factorTrail: (json['factor_trail'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toInt())
|
||||
.toList() ??
|
||||
[],
|
||||
grantToken: json['grant_token'] as String?,
|
||||
accessToken: json['access_token'] as String?,
|
||||
refreshToken: json['refresh_token'] as String?,
|
||||
expiredAt: json['expired_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['expired_at'] as String),
|
||||
availableAt: json['available_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['available_at'] as String),
|
||||
lastGrantAt: json['last_grant_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['last_grant_at'] as String),
|
||||
nonce: json['nonce'] as String?,
|
||||
clientId: (json['client_id'] as num?)?.toInt(),
|
||||
account: Account.fromJson(json['account'] as Map<String, dynamic>),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AuthTicketToJson(AuthTicket instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'location': instance.location,
|
||||
'ip_address': instance.ipAddress,
|
||||
'user_agent': instance.userAgent,
|
||||
'step_remain': instance.stepRemain,
|
||||
'claims': instance.claims,
|
||||
'audiences': instance.audiences,
|
||||
'factor_trail': instance.factorTrail,
|
||||
'grant_token': instance.grantToken,
|
||||
'access_token': instance.accessToken,
|
||||
'refresh_token': instance.refreshToken,
|
||||
'expired_at': instance.expiredAt?.toIso8601String(),
|
||||
'available_at': instance.availableAt?.toIso8601String(),
|
||||
'last_grant_at': instance.lastGrantAt?.toIso8601String(),
|
||||
'nonce': instance.nonce,
|
||||
'client_id': instance.clientId,
|
||||
'account': instance.account.toJson(),
|
||||
'account_id': instance.accountId,
|
||||
};
|
||||
|
||||
AuthFactor _$AuthFactorFromJson(Map<String, dynamic> json) => AuthFactor(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
type: (json['type'] as num).toInt(),
|
||||
config: json['config'] as Map<String, dynamic>?,
|
||||
account: Account.fromJson(json['account'] as Map<String, dynamic>),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$AuthFactorToJson(AuthFactor instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'type': instance.type,
|
||||
'config': instance.config,
|
||||
'account': instance.account.toJson(),
|
||||
'account_id': instance.accountId,
|
||||
};
|
@ -1,6 +1,10 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:livekit_client/livekit_client.dart';
|
||||
import 'package:solian/models/channel.dart';
|
||||
|
||||
part 'call.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Call {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
@ -10,7 +14,8 @@ class Call {
|
||||
String externalId;
|
||||
int founderId;
|
||||
int channelId;
|
||||
List<dynamic> participants;
|
||||
@JsonKey(defaultValue: [])
|
||||
List<dynamic>? participants;
|
||||
Channel channel;
|
||||
|
||||
Call({
|
||||
@ -26,32 +31,9 @@ class Call {
|
||||
required this.channel,
|
||||
});
|
||||
|
||||
factory Call.fromJson(Map<String, dynamic> json) => Call(
|
||||
id: json['id'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'],
|
||||
endedAt:
|
||||
json['ended_at'] != null ? DateTime.parse(json['ended_at']) : null,
|
||||
externalId: json['external_id'],
|
||||
founderId: json['founder_id'],
|
||||
channelId: json['channel_id'],
|
||||
participants: json['participants'] ?? List.empty(),
|
||||
channel: Channel.fromJson(json['channel']),
|
||||
);
|
||||
factory Call.fromJson(Map<String, dynamic> json) => _$CallFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt,
|
||||
'ended_at': endedAt?.toIso8601String(),
|
||||
'external_id': externalId,
|
||||
'founder_id': founderId,
|
||||
'channel_id': channelId,
|
||||
'participants': participants,
|
||||
'channel': channel.toJson(),
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$CallToJson(this);
|
||||
}
|
||||
|
||||
enum ParticipantStatsType {
|
||||
|
37
lib/models/call.g.dart
Normal file
@ -0,0 +1,37 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'call.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Call _$CallFromJson(Map<String, dynamic> json) => Call(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
endedAt: json['ended_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['ended_at'] as String),
|
||||
externalId: json['external_id'] as String,
|
||||
founderId: (json['founder_id'] as num).toInt(),
|
||||
channelId: (json['channel_id'] as num).toInt(),
|
||||
participants: json['participants'] as List<dynamic>? ?? [],
|
||||
channel: Channel.fromJson(json['channel'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$CallToJson(Call instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'ended_at': instance.endedAt?.toIso8601String(),
|
||||
'external_id': instance.externalId,
|
||||
'founder_id': instance.founderId,
|
||||
'channel_id': instance.channelId,
|
||||
'participants': instance.participants,
|
||||
'channel': instance.channel.toJson(),
|
||||
};
|
@ -1,6 +1,10 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
import 'package:solian/models/realm.dart';
|
||||
|
||||
part 'channel.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Channel {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
@ -15,8 +19,10 @@ class Channel {
|
||||
int accountId;
|
||||
Realm? realm;
|
||||
int? realmId;
|
||||
bool isEncrypted;
|
||||
bool isPublic;
|
||||
bool isCommunity;
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: true)
|
||||
bool isAvailable = false;
|
||||
|
||||
Channel({
|
||||
@ -31,49 +37,28 @@ class Channel {
|
||||
required this.members,
|
||||
required this.account,
|
||||
required this.accountId,
|
||||
required this.isEncrypted,
|
||||
required this.isPublic,
|
||||
required this.isCommunity,
|
||||
required this.realm,
|
||||
required this.realmId,
|
||||
});
|
||||
|
||||
factory Channel.fromJson(Map<String, dynamic> json) => Channel(
|
||||
id: json['id'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'],
|
||||
alias: json['alias'],
|
||||
name: json['name'],
|
||||
description: json['description'],
|
||||
type: json['type'],
|
||||
members: json['members']
|
||||
?.map((e) => ChannelMember.fromJson(e))
|
||||
.toList()
|
||||
.cast<ChannelMember>(),
|
||||
account: Account.fromJson(json['account']),
|
||||
accountId: json['account_id'],
|
||||
realm: json['realm'] != null ? Realm.fromJson(json['realm']) : null,
|
||||
realmId: json['realm_id'],
|
||||
isEncrypted: json['is_encrypted'],
|
||||
);
|
||||
factory Channel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ChannelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt,
|
||||
'alias': alias,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'type': type,
|
||||
'members': members?.map((e) => e.toJson()).toList(),
|
||||
'account': account.toJson(),
|
||||
'account_id': accountId,
|
||||
'realm': realm?.toJson(),
|
||||
'realm_id': realmId,
|
||||
'is_encrypted': isEncrypted,
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$ChannelToJson(this);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other is! Channel) return false;
|
||||
return id == other.id;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => id;
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class ChannelMember {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
@ -95,25 +80,8 @@ class ChannelMember {
|
||||
required this.notify,
|
||||
});
|
||||
|
||||
factory ChannelMember.fromJson(Map<String, dynamic> json) => ChannelMember(
|
||||
id: json['id'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'],
|
||||
channelId: json['channel_id'],
|
||||
accountId: json['account_id'],
|
||||
account: Account.fromJson(json['account']),
|
||||
notify: json['notify'],
|
||||
);
|
||||
factory ChannelMember.fromJson(Map<String, dynamic> json) =>
|
||||
_$ChannelMemberFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt,
|
||||
'channel_id': channelId,
|
||||
'account_id': accountId,
|
||||
'account': account.toJson(),
|
||||
'notify': notify,
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$ChannelMemberToJson(this);
|
||||
}
|
||||
|
76
lib/models/channel.g.dart
Normal file
@ -0,0 +1,76 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'channel.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Channel _$ChannelFromJson(Map<String, dynamic> json) => Channel(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
alias: json['alias'] as String,
|
||||
name: json['name'] as String,
|
||||
description: json['description'] as String,
|
||||
type: (json['type'] as num).toInt(),
|
||||
members: (json['members'] as List<dynamic>?)
|
||||
?.map((e) => ChannelMember.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
account: Account.fromJson(json['account'] as Map<String, dynamic>),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
isPublic: json['is_public'] as bool,
|
||||
isCommunity: json['is_community'] as bool,
|
||||
realm: json['realm'] == null
|
||||
? null
|
||||
: Realm.fromJson(json['realm'] as Map<String, dynamic>),
|
||||
realmId: (json['realm_id'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ChannelToJson(Channel instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'alias': instance.alias,
|
||||
'name': instance.name,
|
||||
'description': instance.description,
|
||||
'type': instance.type,
|
||||
'members': instance.members?.map((e) => e.toJson()).toList(),
|
||||
'account': instance.account.toJson(),
|
||||
'account_id': instance.accountId,
|
||||
'realm': instance.realm?.toJson(),
|
||||
'realm_id': instance.realmId,
|
||||
'is_public': instance.isPublic,
|
||||
'is_community': instance.isCommunity,
|
||||
'is_available': instance.isAvailable,
|
||||
};
|
||||
|
||||
ChannelMember _$ChannelMemberFromJson(Map<String, dynamic> json) =>
|
||||
ChannelMember(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
channelId: (json['channel_id'] as num).toInt(),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
account: Account.fromJson(json['account'] as Map<String, dynamic>),
|
||||
notify: (json['notify'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ChannelMemberToJson(ChannelMember instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'channel_id': instance.channelId,
|
||||
'account_id': instance.accountId,
|
||||
'account': instance.account.toJson(),
|
||||
'notify': instance.notify,
|
||||
};
|
49
lib/models/daily_sign.dart
Normal file
@ -0,0 +1,49 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:solian/models/account.dart';
|
||||
|
||||
part 'daily_sign.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class DailySignRecord {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
Account account;
|
||||
int resultTier;
|
||||
int resultExperience;
|
||||
int accountId;
|
||||
|
||||
DailySignRecord({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.resultTier,
|
||||
required this.resultExperience,
|
||||
required this.account,
|
||||
required this.accountId,
|
||||
});
|
||||
|
||||
factory DailySignRecord.fromJson(Map<String, dynamic> json) =>
|
||||
_$DailySignRecordFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$DailySignRecordToJson(this);
|
||||
|
||||
String get symbol => switch (resultTier) {
|
||||
0 => '大\n凶',
|
||||
1 => '凶',
|
||||
2 => '中\n平',
|
||||
3 => '吉',
|
||||
_ => '大\n吉',
|
||||
};
|
||||
|
||||
String get overviewSuggestion => switch (resultTier) {
|
||||
0 => 'dailySignTier0'.tr,
|
||||
1 => 'dailySignTier1'.tr,
|
||||
2 => 'dailySignTier2'.tr,
|
||||
3 => 'dailySignTier3'.tr,
|
||||
_ => 'dailySignTier4'.tr,
|
||||
};
|
||||
}
|
33
lib/models/daily_sign.g.dart
Normal file
@ -0,0 +1,33 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'daily_sign.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
DailySignRecord _$DailySignRecordFromJson(Map<String, dynamic> json) =>
|
||||
DailySignRecord(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
resultTier: (json['result_tier'] as num).toInt(),
|
||||
resultExperience: (json['result_experience'] as num).toInt(),
|
||||
account: Account.fromJson(json['account'] as Map<String, dynamic>),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$DailySignRecordToJson(DailySignRecord instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'account': instance.account.toJson(),
|
||||
'result_tier': instance.resultTier,
|
||||
'result_experience': instance.resultExperience,
|
||||
'account_id': instance.accountId,
|
||||
};
|
@ -1,6 +1,9 @@
|
||||
import 'package:solian/models/account.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:solian/models/channel.dart';
|
||||
|
||||
part 'event.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Event {
|
||||
int id;
|
||||
String uuid;
|
||||
@ -10,10 +13,11 @@ class Event {
|
||||
Map<String, dynamic> body;
|
||||
String type;
|
||||
Channel? channel;
|
||||
Sender sender;
|
||||
ChannelMember sender;
|
||||
int channelId;
|
||||
int senderId;
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: true)
|
||||
bool isPending = false;
|
||||
|
||||
Event({
|
||||
@ -30,40 +34,18 @@ class Event {
|
||||
required this.senderId,
|
||||
});
|
||||
|
||||
factory Event.fromJson(Map<String, dynamic> json) => Event(
|
||||
id: json['id'],
|
||||
uuid: json['uuid'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'],
|
||||
body: json['body'],
|
||||
type: json['type'],
|
||||
channel:
|
||||
json['channel'] != null ? Channel.fromJson(json['channel']) : null,
|
||||
sender: Sender.fromJson(json['sender']),
|
||||
channelId: json['channel_id'],
|
||||
senderId: json['sender_id'],
|
||||
);
|
||||
factory Event.fromJson(Map<String, dynamic> json) => _$EventFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'uuid': uuid,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt,
|
||||
'body': body,
|
||||
'type': type,
|
||||
'channel': channel?.toJson(),
|
||||
'sender': sender.toJson(),
|
||||
'channel_id': channelId,
|
||||
'sender_id': senderId,
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$EventToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class EventMessageBody {
|
||||
@JsonKey(defaultValue: '')
|
||||
String text;
|
||||
@JsonKey(defaultValue: 'plain')
|
||||
String algorithm;
|
||||
List<int>? attachments;
|
||||
List<String>? attachments;
|
||||
int? quoteEvent;
|
||||
int? relatedEvent;
|
||||
List<int>? relatedUsers;
|
||||
@ -78,69 +60,7 @@ class EventMessageBody {
|
||||
});
|
||||
|
||||
factory EventMessageBody.fromJson(Map<String, dynamic> json) =>
|
||||
EventMessageBody(
|
||||
text: json['text'] ?? '',
|
||||
algorithm: json['algorithm'] ?? 'plain',
|
||||
attachments: json['attachments'] != null
|
||||
? List<int>.from(json['attachments'].map((x) => x))
|
||||
: null,
|
||||
quoteEvent: json['quote_event'],
|
||||
relatedEvent: json['related_event'],
|
||||
relatedUsers: json['related_users'] != null
|
||||
? List<int>.from(json['related_users'].map((x) => x))
|
||||
: null,
|
||||
);
|
||||
_$EventMessageBodyFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'text': text,
|
||||
'algorithm': algorithm,
|
||||
'attachments': attachments?.cast<dynamic>(),
|
||||
'quote_event': quoteEvent,
|
||||
'related_event': relatedEvent,
|
||||
'related_users': relatedUsers?.cast<dynamic>(),
|
||||
};
|
||||
}
|
||||
|
||||
class Sender {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
Account account;
|
||||
int channelId;
|
||||
int accountId;
|
||||
int notify;
|
||||
|
||||
Sender({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
this.deletedAt,
|
||||
required this.account,
|
||||
required this.channelId,
|
||||
required this.accountId,
|
||||
required this.notify,
|
||||
});
|
||||
|
||||
factory Sender.fromJson(Map<String, dynamic> json) => Sender(
|
||||
id: json['id'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'],
|
||||
account: Account.fromJson(json['account']),
|
||||
channelId: json['channel_id'],
|
||||
accountId: json['account_id'],
|
||||
notify: json['notify'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt,
|
||||
'account': account.toJson(),
|
||||
'channel_id': channelId,
|
||||
'account_id': accountId,
|
||||
'notify': notify,
|
||||
};
|
||||
Map<String, dynamic> toJson() => _$EventMessageBodyToJson(this);
|
||||
}
|
||||
|
64
lib/models/event.g.dart
Normal file
@ -0,0 +1,64 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'event.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Event _$EventFromJson(Map<String, dynamic> json) => Event(
|
||||
id: (json['id'] as num).toInt(),
|
||||
uuid: json['uuid'] as String,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
body: json['body'] as Map<String, dynamic>,
|
||||
type: json['type'] as String,
|
||||
channel: json['channel'] == null
|
||||
? null
|
||||
: Channel.fromJson(json['channel'] as Map<String, dynamic>),
|
||||
sender: ChannelMember.fromJson(json['sender'] as Map<String, dynamic>),
|
||||
channelId: (json['channel_id'] as num).toInt(),
|
||||
senderId: (json['sender_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$EventToJson(Event instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'uuid': instance.uuid,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'body': instance.body,
|
||||
'type': instance.type,
|
||||
'channel': instance.channel?.toJson(),
|
||||
'sender': instance.sender.toJson(),
|
||||
'channel_id': instance.channelId,
|
||||
'sender_id': instance.senderId,
|
||||
'is_pending': instance.isPending,
|
||||
};
|
||||
|
||||
EventMessageBody _$EventMessageBodyFromJson(Map<String, dynamic> json) =>
|
||||
EventMessageBody(
|
||||
text: json['text'] as String? ?? '',
|
||||
algorithm: json['algorithm'] as String? ?? 'plain',
|
||||
attachments: (json['attachments'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList(),
|
||||
quoteEvent: (json['quote_event'] as num?)?.toInt(),
|
||||
relatedEvent: (json['related_event'] as num?)?.toInt(),
|
||||
relatedUsers: (json['related_users'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toInt())
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$EventMessageBodyToJson(EventMessageBody instance) =>
|
||||
<String, dynamic>{
|
||||
'text': instance.text,
|
||||
'algorithm': instance.algorithm,
|
||||
'attachments': instance.attachments,
|
||||
'quote_event': instance.quoteEvent,
|
||||
'related_event': instance.relatedEvent,
|
||||
'related_users': instance.relatedUsers,
|
||||
};
|
@ -1,83 +0,0 @@
|
||||
class Tag {
|
||||
int id;
|
||||
String alias;
|
||||
String name;
|
||||
String description;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
|
||||
Tag({
|
||||
required this.id,
|
||||
required this.alias,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
});
|
||||
|
||||
factory Tag.fromJson(Map<String, dynamic> json) => Tag(
|
||||
id: json['id'],
|
||||
alias: json['alias'],
|
||||
name: json['name'],
|
||||
description: json['description'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'] != null
|
||||
? DateTime.parse(json['deleted_at'])
|
||||
: null,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'alias': alias,
|
||||
'description': description,
|
||||
'name': name,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
class Category {
|
||||
int id;
|
||||
String alias;
|
||||
String name;
|
||||
String description;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
|
||||
Category({
|
||||
required this.id,
|
||||
required this.alias,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
});
|
||||
|
||||
factory Category.fromJson(Map<String, dynamic> json) => Category(
|
||||
id: json['id'],
|
||||
alias: json['alias'],
|
||||
name: json['name'],
|
||||
description: json['description'],
|
||||
createdAt: DateTime.parse(json['created_at']),
|
||||
updatedAt: DateTime.parse(json['updated_at']),
|
||||
deletedAt: json['deleted_at'] != null
|
||||
? DateTime.parse(json['deleted_at'])
|
||||
: null,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'alias': alias,
|
||||
'description': description,
|
||||
'name': name,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
'deleted_at': deletedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
class Keypair {
|
||||
final String id;
|
||||
final String algorithm;
|
||||
final String publicKey;
|
||||
final String? privateKey;
|
||||
|
||||
final bool isOwned;
|
||||
|
||||
Keypair({
|
||||
required this.id,
|
||||
required this.algorithm,
|
||||
required this.publicKey,
|
||||
required this.privateKey,
|
||||
this.isOwned = false,
|
||||
});
|
||||
|
||||
factory Keypair.fromJson(Map<String, dynamic> json) => Keypair(
|
||||
id: json['id'],
|
||||
algorithm: json['algorithm'],
|
||||
publicKey: json['public_key'],
|
||||
privateKey: json['private_key'],
|
||||
isOwned: json['is_owned'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'algorithm': algorithm,
|
||||
'public_key': publicKey,
|
||||
'private_key': privateKey,
|
||||
'is_owned': isOwned,
|
||||
};
|
||||
}
|
41
lib/models/link.dart
Normal file
@ -0,0 +1,41 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'link.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class LinkMeta {
|
||||
int id;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
DateTime? deletedAt;
|
||||
String entryId;
|
||||
String? icon;
|
||||
String url;
|
||||
String? title;
|
||||
String? image;
|
||||
String? video;
|
||||
String? audio;
|
||||
String? description;
|
||||
String? siteName;
|
||||
|
||||
LinkMeta({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.entryId,
|
||||
required this.icon,
|
||||
required this.url,
|
||||
required this.title,
|
||||
required this.image,
|
||||
required this.video,
|
||||
required this.audio,
|
||||
required this.description,
|
||||
required this.siteName,
|
||||
});
|
||||
|
||||
factory LinkMeta.fromJson(Map<String, dynamic> json) =>
|
||||
_$LinkMetaFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$LinkMetaToJson(this);
|
||||
}
|
41
lib/models/link.g.dart
Normal file
@ -0,0 +1,41 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'link.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
LinkMeta _$LinkMetaFromJson(Map<String, dynamic> json) => LinkMeta(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
entryId: json['entry_id'] as String,
|
||||
icon: json['icon'] as String?,
|
||||
url: json['url'] as String,
|
||||
title: json['title'] as String?,
|
||||
image: json['image'] as String?,
|
||||
video: json['video'] as String?,
|
||||
audio: json['audio'] as String?,
|
||||
description: json['description'] as String?,
|
||||
siteName: json['site_name'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$LinkMetaToJson(LinkMeta instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'entry_id': instance.entryId,
|
||||
'icon': instance.icon,
|
||||
'url': instance.url,
|
||||
'title': instance.title,
|
||||
'image': instance.image,
|
||||
'video': instance.video,
|
||||
'audio': instance.audio,
|
||||
'description': instance.description,
|
||||
'site_name': instance.siteName,
|
||||
};
|