Compare commits
14 Commits
40b885b27b
...
1.2.1+38
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a2d94cedf | |||
| 780f7c22bc | |||
| c18ce88993 | |||
| 73456fcff6 | |||
| 8e8be52658 | |||
| df22b65777 | |||
| 1437414b7f | |||
| c1ff317c66 | |||
| f3375070a0 | |||
| 204df3306e | |||
| aeaade9590 | |||
| 306ce9e2b4 | |||
| a487924300 | |||
| ad66c11593 |
@@ -3,6 +3,7 @@
|
||||
<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" />
|
||||
@@ -84,6 +85,11 @@
|
||||
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
|
||||
|
||||
BIN
android/app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
@@ -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 |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
||||
@@ -3,6 +3,7 @@
|
||||
"hide": "Hide",
|
||||
"okay": "Okay",
|
||||
"next": "Next",
|
||||
"prev": "Previous",
|
||||
"reset": "Reset",
|
||||
"page": "Page",
|
||||
"home": "Home",
|
||||
@@ -54,6 +55,8 @@
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"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",
|
||||
@@ -68,8 +71,12 @@
|
||||
"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",
|
||||
@@ -101,6 +108,11 @@
|
||||
"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!",
|
||||
@@ -373,7 +385,8 @@
|
||||
"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.",
|
||||
"messageHistoryWipe": "Wipe local message history",
|
||||
"localDatabaseWipe": "Wipe local database",
|
||||
"localDatabaseSize": "Overall database size: @size",
|
||||
"unknown": "Unknown",
|
||||
"collapse": "Collapse",
|
||||
"expand": "Expand",
|
||||
@@ -392,5 +405,7 @@
|
||||
"userLevel11": "Legend",
|
||||
"userLevel12": "Mythic",
|
||||
"userLevel13": "Immortal",
|
||||
"postBrowsingIn": "Browsing in @region"
|
||||
"postBrowsingIn": "Browsing in @region",
|
||||
"needRestartToApply": "Restart the application to take effect",
|
||||
"holdToSeeDetail": "Long press / Mouse hover to see detail"
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"okay": "确认",
|
||||
"home": "首页",
|
||||
"next": "下一步",
|
||||
"prev": "上一步",
|
||||
"reset": "重置",
|
||||
"cancel": "取消",
|
||||
"confirm": "确认",
|
||||
@@ -14,6 +15,8 @@
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"settings": "设置",
|
||||
"settingsNotificationBgService": "常驻通知服务",
|
||||
"settingsNotificationBgServiceDesc": "在设备常驻一个通知服务,使得部分不支持推送通知的设备可以在后台收到通知;启用该功能的情况下不会向服务器注册推送通知,并且你会始终在他人眼中成为在线(隐身除外);可能需要在设置中关闭电量与流量优化。",
|
||||
"page": "页面",
|
||||
"draft": "草稿",
|
||||
"draftSave": "存为草稿",
|
||||
@@ -73,8 +76,12 @@
|
||||
"forgotPassword": "忘记密码",
|
||||
"email": "邮件地址",
|
||||
"username": "用户名",
|
||||
"usernameInputHint": "同时支持邮箱 / 电话号码",
|
||||
"nickname": "显示名",
|
||||
"password": "密码",
|
||||
"passwordOneTime": "一次性验证码",
|
||||
"passwordInputHint": "忘记密码了?回到第一步以重置密码",
|
||||
"passwordOneTimeInputHint": "检查你的收件箱或是授权器获得以验证码",
|
||||
"title": "标题",
|
||||
"description": "简介",
|
||||
"birthday": "生日",
|
||||
@@ -106,6 +113,11 @@
|
||||
"signinRiskDetected": "检测到风险,点击下一步按钮来打开一个网页,并通过在其上面登录来通过安全检查。",
|
||||
"signinResetPasswordHint": "请先填写用户名以发送重置密码请求。",
|
||||
"signinResetPasswordSent": "重置密码请求已发送,在绑定邮件收件箱可收取一份包含重置密码链接的邮件。",
|
||||
"signinPickFactor": "选择一个\n验证方式",
|
||||
"signinEnterPassword": "输入密码\n或验证码",
|
||||
"signinMultiFactor": "@n 步验证",
|
||||
"authFactorEmail": "邮箱一次性密码",
|
||||
"authFactorPassword": "账户密码",
|
||||
"signup": "注册",
|
||||
"signupGreeting": "欢迎加入\nSolar Network",
|
||||
"signupCaption": "在 Solarpass 注册一个账号以获得整个 Solar Network 的存取权!",
|
||||
@@ -374,7 +386,8 @@
|
||||
"callStatusReconnected": "重连中",
|
||||
"messageOutOfSync": "消息可能与服务器脱节",
|
||||
"messageOutOfSyncCaption": "由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。",
|
||||
"messageHistoryWipe": "清除消息记录",
|
||||
"localDatabaseWipe": "清除本地数据库",
|
||||
"localDatabaseSize": "本地数据库大小:@size",
|
||||
"unknown": "未知",
|
||||
"collapse": "折叠",
|
||||
"expand": "展开",
|
||||
@@ -393,5 +406,7 @@
|
||||
"userLevel11": "名垂千古",
|
||||
"userLevel12": "独占鳌头",
|
||||
"userLevel13": "万古流芳",
|
||||
"postBrowsingIn": "浏览 @region 内的帖子中"
|
||||
"postBrowsingIn": "浏览 @region 内的帖子中",
|
||||
"needRestartToApply": "需要重启应用来生效",
|
||||
"holdToSeeDetail": "长按 / 鼠标悬浮来查看详情"
|
||||
}
|
||||
|
||||
@@ -154,8 +154,12 @@ PODS:
|
||||
- PromisesSwift (~> 2.1)
|
||||
- FirebaseSharedSwift (11.1.0)
|
||||
- Flutter (1.0.0)
|
||||
- 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):
|
||||
@@ -302,7 +306,9 @@ DEPENDENCIES:
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- firebase_performance (from `.symlinks/plugins/firebase_performance/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- 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_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`)
|
||||
@@ -377,8 +383,12 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/firebase_performance/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
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:
|
||||
@@ -454,7 +464,9 @@ SPEC CHECKSUMS:
|
||||
FirebaseSessions: 78f137e68dc01ca71606169ba4ac73b98c13752a
|
||||
FirebaseSharedSwift: 260a35e08943ec810d820a70bc0359136351d0c5
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_background_service_ios: e30e0d3ee69e4cee66272d0c78eacd48c2e94aac
|
||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||
flutter_webrtc: 75b868e4f9e817c7a9a42ca4b6169063de4eec9f
|
||||
|
||||
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',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
(
|
||||
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(() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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/database/database.dart';
|
||||
import 'package:solian/providers/database/services/messages.dart';
|
||||
|
||||
@@ -31,79 +30,32 @@ class ChatEventController {
|
||||
this.channel = channel;
|
||||
this.scope = scope;
|
||||
|
||||
syncLocal(channel);
|
||||
|
||||
isLoading.value = true;
|
||||
if (PlatformInfo.isWeb) {
|
||||
final result = await src.fetchRemoteEvents(
|
||||
channel,
|
||||
scope,
|
||||
depth: 1,
|
||||
offset: 0,
|
||||
);
|
||||
await syncLocal(channel, take: 10);
|
||||
|
||||
src.pullRemoteEvents(channel, scope: scope, take: 10).then((result) {
|
||||
totalEvents.value = result?.$2 ?? 0;
|
||||
if (result != null) {
|
||||
for (final x in result.$1.reversed) {
|
||||
final entry = LocalMessageEventTableData(
|
||||
id: x.id,
|
||||
channelId: x.channelId,
|
||||
createdAt: x.createdAt,
|
||||
data: x,
|
||||
);
|
||||
insertEvent(entry);
|
||||
applyEvent(entry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final result = await src.pullRemoteEvents(
|
||||
channel,
|
||||
scope: scope,
|
||||
depth: 1,
|
||||
);
|
||||
totalEvents.value = result?.$2 ?? 0;
|
||||
await syncLocal(channel);
|
||||
}
|
||||
syncLocal(channel, take: 10);
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> loadEvents(Channel channel, String scope) async {
|
||||
const take = 20;
|
||||
final offset = currentEvents.length;
|
||||
|
||||
isLoading.value = true;
|
||||
if (PlatformInfo.isWeb) {
|
||||
final result = await src.fetchRemoteEvents(
|
||||
channel,
|
||||
scope,
|
||||
depth: 3,
|
||||
offset: currentEvents.length,
|
||||
);
|
||||
if (result != null) {
|
||||
totalEvents.value = result.$2;
|
||||
for (final x in result.$1.reversed) {
|
||||
final entry = LocalMessageEventTableData(
|
||||
id: x.id,
|
||||
channelId: x.channelId,
|
||||
createdAt: x.createdAt,
|
||||
data: x,
|
||||
);
|
||||
currentEvents.add(entry);
|
||||
applyEvent(entry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final result = await src.pullRemoteEvents(
|
||||
channel,
|
||||
depth: 3,
|
||||
scope: scope,
|
||||
offset: currentEvents.length,
|
||||
);
|
||||
await syncLocal(channel, take: take, offset: offset);
|
||||
src.pullRemoteEvents(channel, scope: scope, 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 src.listEvents(channel);
|
||||
Future<bool> syncLocal(Channel channel,
|
||||
{required int take, int offset = 0}) async {
|
||||
final data = await src.listEvents(channel, take: take, offset: offset);
|
||||
currentEvents.replaceRange(0, currentEvents.length, data);
|
||||
for (final x in data.reversed) {
|
||||
applyEvent(x);
|
||||
@@ -113,16 +65,7 @@ class ChatEventController {
|
||||
|
||||
receiveEvent(Event remote) async {
|
||||
LocalMessageEventTableData entry;
|
||||
if (PlatformInfo.isWeb) {
|
||||
entry = LocalMessageEventTableData(
|
||||
id: remote.id,
|
||||
channelId: remote.channelId,
|
||||
createdAt: remote.createdAt,
|
||||
data: remote,
|
||||
);
|
||||
} else {
|
||||
entry = await src.receiveEvent(remote);
|
||||
}
|
||||
entry = await src.receiveEvent(remote);
|
||||
|
||||
totalEvents.value++;
|
||||
insertEvent(entry);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:solian/exceptions/request.dart';
|
||||
import 'package:solian/exceptions/unauthorized.dart';
|
||||
|
||||
extension SolianExtenions on BuildContext {
|
||||
extension AppExtensions on BuildContext {
|
||||
void showSnackbar(String content, {SnackBarAction? action}) {
|
||||
ScaffoldMessenger.of(this).showSnackBar(SnackBar(
|
||||
content: Text(content),
|
||||
@@ -102,3 +104,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,12 +2,13 @@ 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:protocol_handler/protocol_handler.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:solian/background.dart';
|
||||
import 'package:solian/bootstrapper.dart';
|
||||
import 'package:solian/firebase_options.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
@@ -41,6 +42,7 @@ void main() async {
|
||||
await Future.wait([
|
||||
_initializeFirebase(),
|
||||
_initializePlatformComponents(),
|
||||
_initializeBackgroundNotificationService(),
|
||||
]);
|
||||
|
||||
GoRouter.optionURLReflectsImperativeAPIs = true;
|
||||
@@ -64,6 +66,11 @@ Future<void> _initializeFirebase() async {
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> _initializeBackgroundNotificationService() async {
|
||||
autoConfigureBackgroundNotificationService();
|
||||
autoStartBackgroundNotificationService();
|
||||
}
|
||||
|
||||
Future<void> _initializePlatformComponents() async {
|
||||
if (!PlatformInfo.isWeb) {
|
||||
await protocolHandler.register('solink');
|
||||
@@ -144,5 +151,7 @@ class SolianApp extends StatelessWidget {
|
||||
Get.lazyPut(() => LinkExpandProvider());
|
||||
Get.lazyPut(() => DailySignProvider());
|
||||
Get.lazyPut(() => LastReadProvider());
|
||||
|
||||
Get.find<WebSocketProvider>().requestPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
103
lib/models/auth.dart
Normal file
@@ -0,0 +1,103 @@
|
||||
import 'package:freezed_annotation/freezed_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,
|
||||
};
|
||||
@@ -37,7 +37,7 @@ class StatusProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
return await client.get('/users/me/status');
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class StatusProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final payload = {
|
||||
'type': type,
|
||||
@@ -85,7 +85,7 @@ class StatusProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.delete('/users/me/status');
|
||||
if (resp.statusCode != 200) {
|
||||
|
||||
@@ -6,8 +6,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_connect/http/src/request/request.dart';
|
||||
import 'package:solian/background.dart';
|
||||
import 'package:solian/exceptions/request.dart';
|
||||
import 'package:solian/exceptions/unauthorized.dart';
|
||||
import 'package:solian/models/auth.dart';
|
||||
import 'package:solian/providers/database/database.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/services.dart';
|
||||
|
||||
@@ -112,14 +115,14 @@ class AuthProvider extends GetConnect {
|
||||
return request;
|
||||
}
|
||||
|
||||
GetConnect configureClient(
|
||||
Future<GetConnect> configureClient(
|
||||
String service, {
|
||||
timeout = const Duration(seconds: 5),
|
||||
}) {
|
||||
}) async {
|
||||
final client = GetConnect(
|
||||
maxAuthRetries: 3,
|
||||
timeout: timeout,
|
||||
userAgent: 'Solian/1.1',
|
||||
userAgent: await ServiceFinder.getUserAgent(),
|
||||
sendUserAgent: true,
|
||||
);
|
||||
client.httpClient.addAuthenticator(requestAuthenticator);
|
||||
@@ -146,27 +149,13 @@ class AuthProvider extends GetConnect {
|
||||
|
||||
Future<TokenSet> signin(
|
||||
BuildContext context,
|
||||
String username,
|
||||
String password,
|
||||
AuthTicket ticket,
|
||||
) async {
|
||||
userProfile.value = null;
|
||||
|
||||
final client = ServiceFinder.configureClient('auth');
|
||||
|
||||
// Create ticket
|
||||
final resp = await client.post('/auth', {
|
||||
'username': username,
|
||||
'password': password,
|
||||
});
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
} else if (resp.body['is_finished'] == false) {
|
||||
throw RiskyAuthenticateException(resp.body['ticket']['id']);
|
||||
}
|
||||
|
||||
// Assign token
|
||||
final tokenResp = await post('/auth/token', {
|
||||
'code': resp.body['ticket']['grant_token'],
|
||||
'code': ticket.grantToken!,
|
||||
'grant_type': 'grant_token',
|
||||
});
|
||||
if (tokenResp.statusCode != 200) {
|
||||
@@ -198,6 +187,9 @@ class AuthProvider extends GetConnect {
|
||||
Get.find<WebSocketProvider>().notifications.clear();
|
||||
Get.find<WebSocketProvider>().notificationUnread.value = 0;
|
||||
|
||||
AppDatabase.removeDatabase();
|
||||
autoStopBackgroundNotificationService();
|
||||
|
||||
storage.deleteAll();
|
||||
}
|
||||
|
||||
@@ -211,7 +203,8 @@ class AuthProvider extends GetConnect {
|
||||
}
|
||||
|
||||
Future<void> refreshUserProfile() async {
|
||||
final client = configureClient('auth');
|
||||
if (!isAuthorized.value) return;
|
||||
final client = await configureClient('auth');
|
||||
final resp = await client.get('/users/me');
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
|
||||
@@ -92,7 +92,7 @@ class ChatCallProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.post(
|
||||
'/channels/global/${channel.value!.alias}/calls/ongoing/token',
|
||||
|
||||
@@ -93,7 +93,7 @@ class AttachmentProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient(
|
||||
final client = await auth.configureClient(
|
||||
'uc',
|
||||
timeout: const Duration(minutes: 3),
|
||||
);
|
||||
@@ -135,7 +135,7 @@ class AttachmentProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('uc');
|
||||
final client = await auth.configureClient('uc');
|
||||
|
||||
final fileAlt = basename(path).contains('.')
|
||||
? basename(path).substring(0, basename(path).lastIndexOf('.'))
|
||||
@@ -173,7 +173,7 @@ class AttachmentProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient(
|
||||
final client = await auth.configureClient(
|
||||
'uc',
|
||||
timeout: const Duration(minutes: 3),
|
||||
);
|
||||
@@ -198,7 +198,7 @@ class AttachmentProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('files');
|
||||
final client = await auth.configureClient('files');
|
||||
|
||||
var resp = await client.put('/attachments/$id', {
|
||||
'alt': alt,
|
||||
@@ -217,7 +217,7 @@ class AttachmentProvider extends GetConnect {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('files');
|
||||
final client = await auth.configureClient('files');
|
||||
|
||||
var resp = await client.delete('/attachments/$id');
|
||||
if (resp.statusCode != 200) {
|
||||
|
||||
@@ -33,7 +33,7 @@ class ChannelProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get('/channels/$realm/$alias');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -48,7 +48,7 @@ class ChannelProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get('/channels/$realm/$alias/me');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -63,7 +63,7 @@ class ChannelProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get('/channels/$realm/$alias/calls/ongoing');
|
||||
if (resp.statusCode == 404) {
|
||||
@@ -79,7 +79,7 @@ class ChannelProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get('/channels/$scope');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -93,7 +93,7 @@ class ChannelProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get('/channels/$realm/me/available');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -107,7 +107,7 @@ class ChannelProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.post('/channels/$scope', payload);
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -132,7 +132,7 @@ class ChannelProvider extends GetxController {
|
||||
if (related == null) return null;
|
||||
|
||||
final prof = auth.userProfile.value!;
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.post('/channels/$scope/dm', {
|
||||
'alias': const Uuid().v4().replaceAll('-', '').substring(0, 12),
|
||||
@@ -153,7 +153,7 @@ class ChannelProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.put('/channels/$scope/$id', payload);
|
||||
if (resp.statusCode != 200) {
|
||||
|
||||
@@ -14,9 +14,9 @@ class PostProvider extends GetConnect {
|
||||
GetConnect client;
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.value) {
|
||||
client = auth.configureClient('co');
|
||||
client = await auth.configureClient('co');
|
||||
} else {
|
||||
client = ServiceFinder.configureClient('co');
|
||||
client = await ServiceFinder.configureClient('co');
|
||||
}
|
||||
final resp = await client.get('/whats-new?pivot=$pivot');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -36,9 +36,9 @@ class PostProvider extends GetConnect {
|
||||
if (realm != null) 'realm=$realm',
|
||||
];
|
||||
if (auth.isAuthorized.value) {
|
||||
client = auth.configureClient('co');
|
||||
client = await auth.configureClient('co');
|
||||
} else {
|
||||
client = ServiceFinder.configureClient('co');
|
||||
client = await ServiceFinder.configureClient('co');
|
||||
}
|
||||
final resp = await client.get(
|
||||
channel == null
|
||||
@@ -60,7 +60,7 @@ class PostProvider extends GetConnect {
|
||||
'take=${10}',
|
||||
'offset=$page',
|
||||
];
|
||||
final client = auth.configureClient('interactive');
|
||||
final client = await auth.configureClient('interactive');
|
||||
final resp = await client.get('/posts/drafts?${queries.join('&')}');
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
|
||||
@@ -25,7 +25,7 @@ class RealmProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.get('/realms/$alias');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -39,7 +39,7 @@ class RealmProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.get('/realms/me/available');
|
||||
if (resp.statusCode != 200) {
|
||||
|
||||
@@ -10,7 +10,7 @@ class DailySignProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('id');
|
||||
final client = await auth.configureClient('id');
|
||||
|
||||
final resp = await client.get('/daily?take=$take');
|
||||
if (resp.statusCode != 200 && resp.statusCode != 404) {
|
||||
@@ -30,7 +30,7 @@ class DailySignProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('id');
|
||||
final client = await auth.configureClient('id');
|
||||
|
||||
final resp = await client.get('/daily/today');
|
||||
if (resp.statusCode != 200 && resp.statusCode != 404) {
|
||||
@@ -46,7 +46,7 @@ class DailySignProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = auth.configureClient('id');
|
||||
final client = await auth.configureClient('id');
|
||||
|
||||
final resp = await client.post('/daily', {});
|
||||
if (resp.statusCode != 200) {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift_flutter/drift_flutter.dart';
|
||||
import 'package:get/get.dart' hide Value;
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
import 'package:solian/providers/database/tables/messages.dart';
|
||||
|
||||
import 'package:solian/models/event.dart';
|
||||
@@ -15,10 +20,32 @@ class AppDatabase extends _$AppDatabase {
|
||||
int get schemaVersion => 1;
|
||||
|
||||
static QueryExecutor _openConnection() {
|
||||
return driftDatabase(name: 'solar_network_local_db');
|
||||
return driftDatabase(
|
||||
name: 'solar_network_local_db',
|
||||
web: DriftWebOptions(
|
||||
sqlite3Wasm: Uri.parse('sqlite3.wasm'),
|
||||
driftWorker: Uri.parse('drift_worker.dart.js'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<int> getDatabaseSize() async {
|
||||
if (PlatformInfo.isWeb) return 0;
|
||||
final basepath = await getApplicationDocumentsDirectory();
|
||||
return await File(join(basepath.path, 'solar_network_local_db.sqlite'))
|
||||
.length();
|
||||
}
|
||||
|
||||
static Future<void> removeDatabase() async {
|
||||
if (PlatformInfo.isWeb) return;
|
||||
final basepath = await getApplicationDocumentsDirectory();
|
||||
final file = File(join(basepath.path, 'solar_network_local_db.sqlite'));
|
||||
await Get.find<DatabaseProvider>().database.close();
|
||||
await file.delete();
|
||||
Get.find<DatabaseProvider>().database = AppDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
class DatabaseProvider extends GetxController {
|
||||
final database = AppDatabase();
|
||||
var database = AppDatabase();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class MessagesFetchingProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return null;
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get(
|
||||
'/whats-new?pivot=$pivot&take=$take',
|
||||
@@ -33,7 +33,7 @@ class MessagesFetchingProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return null;
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get(
|
||||
'/channels/$scope/${channel.alias}/events/$id',
|
||||
@@ -51,19 +51,13 @@ class MessagesFetchingProvider extends GetxController {
|
||||
Future<(List<Event>, int)?> fetchRemoteEvents(
|
||||
Channel channel,
|
||||
String scope, {
|
||||
required int depth,
|
||||
bool Function(List<Event> items)? onBrake,
|
||||
take = 10,
|
||||
offset = 0,
|
||||
}) async {
|
||||
if (depth <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return null;
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get(
|
||||
'/channels/$scope/${channel.alias}/events?take=$take&offset=$offset',
|
||||
@@ -77,21 +71,7 @@ class MessagesFetchingProvider extends GetxController {
|
||||
final result =
|
||||
response.data?.map((e) => Event.fromJson(e)).toList() ?? List.empty();
|
||||
|
||||
if (onBrake != null && onBrake(result)) {
|
||||
return (result, response.count);
|
||||
}
|
||||
|
||||
final expandResult = (await fetchRemoteEvents(
|
||||
channel,
|
||||
scope,
|
||||
depth: depth - 1,
|
||||
take: take,
|
||||
offset: offset + result.length,
|
||||
))
|
||||
?.$1 ??
|
||||
List.empty();
|
||||
|
||||
return ([...result, ...expandResult], response.count);
|
||||
return (result, response.count);
|
||||
}
|
||||
|
||||
Future<LocalMessageEventTableData> receiveEvent(Event remote) async {
|
||||
@@ -151,22 +131,14 @@ class MessagesFetchingProvider extends GetxController {
|
||||
|
||||
/// Pull the remote events to local database
|
||||
Future<(List<Event>, int)?> pullRemoteEvents(Channel channel,
|
||||
{String scope = 'global', depth = 10, offset = 0}) async {
|
||||
{String scope = 'global', take = 10, offset = 0}) async {
|
||||
final database = Get.find<DatabaseProvider>().database;
|
||||
final lastOne = await (database.select(database.localMessageEventTable)
|
||||
..where((x) => x.channelId.equals(channel.id))
|
||||
..orderBy([(t) => OrderingTerm.desc(t.id)])
|
||||
..limit(1))
|
||||
.getSingleOrNull();
|
||||
|
||||
final data = await fetchRemoteEvents(
|
||||
channel,
|
||||
scope,
|
||||
depth: depth,
|
||||
offset: offset,
|
||||
onBrake: (items) {
|
||||
return items.any((x) => x.id == lastOne?.id);
|
||||
},
|
||||
take: take,
|
||||
);
|
||||
if (data != null) {
|
||||
await database.batch((batch) {
|
||||
@@ -185,11 +157,13 @@ class MessagesFetchingProvider extends GetxController {
|
||||
return data;
|
||||
}
|
||||
|
||||
Future<List<LocalMessageEventTableData>> listEvents(Channel channel) async {
|
||||
Future<List<LocalMessageEventTableData>> listEvents(Channel channel,
|
||||
{required int take, int offset = 0}) async {
|
||||
final database = Get.find<DatabaseProvider>().database;
|
||||
return await (database.select(database.localMessageEventTable)
|
||||
..where((x) => x.channelId.equals(channel.id))
|
||||
..orderBy([(t) => OrderingTerm.desc(t.id)]))
|
||||
..orderBy([(t) => OrderingTerm.desc(t.id)])
|
||||
..limit(take, offset: offset))
|
||||
.get();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class LinkExpandProvider extends GetxController {
|
||||
log('[LinkExpander] Expanding link... $url');
|
||||
final target = utf8.fuse(base64).encode(url);
|
||||
if (_cachedResponse.containsKey(target)) return _cachedResponse[target];
|
||||
final client = ServiceFinder.configureClient('dealer');
|
||||
final client = await ServiceFinder.configureClient('dealer');
|
||||
final resp = await client.get('/api/links/$target');
|
||||
if (resp.statusCode != 200) {
|
||||
log('Unable to expand link ($url), status: ${resp.statusCode}, response: ${resp.body}');
|
||||
|
||||
@@ -26,21 +26,21 @@ class RelationshipProvider extends GetxController {
|
||||
return _friends.any((x) => x.relatedId == account.id);
|
||||
}
|
||||
|
||||
Future<Response> listRelation() {
|
||||
Future<Response> listRelation() async {
|
||||
final AuthProvider auth = Get.find();
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
return client.get('/users/me/relations');
|
||||
}
|
||||
|
||||
Future<Response> listRelationWithStatus(int status) {
|
||||
Future<Response> listRelationWithStatus(int status) async {
|
||||
final AuthProvider auth = Get.find();
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
return client.get('/users/me/relations?status=$status');
|
||||
}
|
||||
|
||||
Future<Response> makeFriend(String username) async {
|
||||
final AuthProvider auth = Get.find();
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
final resp = await client.post('/users/me/relations?related=$username', {});
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
@@ -52,7 +52,7 @@ class RelationshipProvider extends GetxController {
|
||||
Future<Response> handleRelation(
|
||||
Relationship relationship, bool doAccept) async {
|
||||
final AuthProvider auth = Get.find();
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
final resp = await client.post(
|
||||
'/users/me/relations/${relationship.relatedId}/${doAccept ? 'accept' : 'decline'}',
|
||||
{},
|
||||
@@ -66,7 +66,7 @@ class RelationshipProvider extends GetxController {
|
||||
|
||||
Future<Response> editRelation(Relationship relationship, int status) async {
|
||||
final AuthProvider auth = Get.find();
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
final resp = await client.patch(
|
||||
'/users/me/relations/${relationship.relatedId}',
|
||||
{'status': status},
|
||||
|
||||
@@ -11,7 +11,7 @@ class StickerProvider extends GetxController {
|
||||
availableStickers.clear();
|
||||
aliasImageMapping.clear();
|
||||
|
||||
final client = ServiceFinder.configureClient('files');
|
||||
final client = await ServiceFinder.configureClient('files');
|
||||
final resp = await client.get(
|
||||
'/stickers/manifest?take=100',
|
||||
);
|
||||
|
||||
@@ -5,7 +5,9 @@ import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.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/exceptions/request.dart';
|
||||
import 'package:solian/models/notification.dart';
|
||||
import 'package:solian/models/packet.dart';
|
||||
@@ -29,20 +31,46 @@ class WebSocketProvider extends GetxController {
|
||||
|
||||
@override
|
||||
onInit() {
|
||||
FirebaseMessaging.instance
|
||||
.requestPermission(
|
||||
alert: true,
|
||||
announcement: true,
|
||||
carPlay: true,
|
||||
badge: true,
|
||||
sound: true)
|
||||
.then((status) {
|
||||
notifyPrefetch();
|
||||
});
|
||||
notifyPrefetch();
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void requestPermissions() {
|
||||
try {
|
||||
FirebaseMessaging.instance.requestPermission(
|
||||
alert: true,
|
||||
announcement: true,
|
||||
carPlay: true,
|
||||
badge: true,
|
||||
sound: true);
|
||||
} catch (_) {
|
||||
// When firebase isn't initialized (background service)
|
||||
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.requestNotificationsPermission();
|
||||
flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<
|
||||
IOSFlutterLocalNotificationsPlugin>()
|
||||
?.requestPermissions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
);
|
||||
flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<
|
||||
MacOSFlutterLocalNotificationsPlugin>()
|
||||
?.requestPermissions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> connect({noRetry = false}) async {
|
||||
if (isConnected.value) {
|
||||
return;
|
||||
@@ -90,6 +118,10 @@ class WebSocketProvider extends GetxController {
|
||||
final packet = NetworkPackage.fromJson(jsonDecode(event));
|
||||
log('Websocket incoming message: ${packet.method} ${packet.message}');
|
||||
stream.sink.add(packet);
|
||||
if (packet.method == 'notifications.new') {
|
||||
notifications.add(Notification.fromJson(packet.payload!));
|
||||
notificationUnread.value++;
|
||||
}
|
||||
},
|
||||
onDone: () {
|
||||
isConnected.value = false;
|
||||
@@ -106,7 +138,7 @@ class WebSocketProvider extends GetxController {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return;
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.get('/notifications?skip=0&take=100');
|
||||
if (resp.statusCode == 200) {
|
||||
@@ -120,6 +152,14 @@ class WebSocketProvider extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> registerPushNotifications() async {
|
||||
if (PlatformInfo.isWeb) return;
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool('service_background_notification') == true) {
|
||||
log('Background notification service has been enabled, skip register push notifications');
|
||||
return;
|
||||
}
|
||||
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return;
|
||||
|
||||
@@ -142,7 +182,7 @@ class WebSocketProvider extends GetxController {
|
||||
}
|
||||
log('Device Push Token is $token');
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.post('/notifications/subscribe', {
|
||||
'provider': provider,
|
||||
|
||||
@@ -8,6 +8,8 @@ import 'package:solian/screens/account/friend.dart';
|
||||
import 'package:solian/screens/account/personalize.dart';
|
||||
import 'package:solian/screens/account/profile_page.dart';
|
||||
import 'package:solian/screens/account/stickers.dart';
|
||||
import 'package:solian/screens/auth/signin.dart';
|
||||
import 'package:solian/screens/auth/signup.dart';
|
||||
import 'package:solian/screens/channel/channel_chat.dart';
|
||||
import 'package:solian/screens/channel/channel_detail.dart';
|
||||
import 'package:solian/screens/channel/channel_organize.dart';
|
||||
@@ -259,6 +261,24 @@ abstract class AppRouter {
|
||||
name: state.pathParameters['name']!,
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/auth/sign-in',
|
||||
name: 'signin',
|
||||
builder: (context, state) => TitleShell(
|
||||
state: state,
|
||||
isCenteredTitle: true,
|
||||
child: const SignInScreen(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/auth/sign-up',
|
||||
name: 'signup',
|
||||
builder: (context, state) => TitleShell(
|
||||
state: state,
|
||||
isCenteredTitle: true,
|
||||
child: const SignUpScreen(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/account_status.dart';
|
||||
import 'package:solian/providers/relation.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/screens/auth/signin.dart';
|
||||
import 'package:solian/screens/auth/signup.dart';
|
||||
import 'package:solian/widgets/account/account_heading.dart';
|
||||
import 'package:solian/widgets/sized_container.dart';
|
||||
import 'package:badges/badges.dart' as badges;
|
||||
@@ -73,13 +71,7 @@ class _AccountScreenState extends State<AccountScreen> {
|
||||
title: 'signin'.tr,
|
||||
caption: 'signinCaption'.tr,
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
isDismissible: false,
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (context) => const SignInPopup(),
|
||||
).then((val) async {
|
||||
AppRouter.instance.pushNamed('signin').then((val) async {
|
||||
if (val == true) {
|
||||
await auth.refreshUserProfile();
|
||||
}
|
||||
@@ -94,13 +86,7 @@ class _AccountScreenState extends State<AccountScreen> {
|
||||
title: 'signup'.tr,
|
||||
caption: 'signupCaption'.tr,
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
isDismissible: false,
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (context) => const SignUpPopup(),
|
||||
).then((_) {
|
||||
AppRouter.instance.pushNamed('signup').then((_) {
|
||||
setState(() {});
|
||||
});
|
||||
},
|
||||
@@ -219,7 +205,6 @@ class _ActionCard extends StatelessWidget {
|
||||
final Function onTap;
|
||||
|
||||
const _ActionCard({
|
||||
super.key,
|
||||
required this.onTap,
|
||||
required this.title,
|
||||
required this.caption,
|
||||
|
||||
@@ -31,7 +31,7 @@ class _NotificationScreenState extends State<NotificationScreen> {
|
||||
}
|
||||
|
||||
if (markList.isNotEmpty) {
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
await client.put('/notifications/read', {'messages': markList});
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class _NotificationScreenState extends State<NotificationScreen> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
await client.put('/notifications/read/${element.id}', {});
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> {
|
||||
return;
|
||||
}
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.put(
|
||||
'/users/me/$position',
|
||||
@@ -148,7 +148,7 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
_birthday?.toIso8601String();
|
||||
final resp = await client.put(
|
||||
|
||||
@@ -46,7 +46,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
Future<void> _getUserinfo() async {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
var client = ServiceFinder.configureClient('auth');
|
||||
var client = await ServiceFinder.configureClient('auth');
|
||||
var resp = await client.get('/users/${widget.name}');
|
||||
if (resp.statusCode != 200) {
|
||||
context.showErrorDialog(resp.bodyString).then((_) {
|
||||
@@ -56,7 +56,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
_userinfo = Account.fromJson(resp.body);
|
||||
}
|
||||
|
||||
client = ServiceFinder.configureClient('interactive');
|
||||
client = await ServiceFinder.configureClient('interactive');
|
||||
resp = await client.get('/users/${widget.name}');
|
||||
if (resp.statusCode != 200) {
|
||||
context.showErrorDialog(resp.bodyString).then((_) {
|
||||
@@ -71,7 +71,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
}
|
||||
|
||||
Future<void> getPinnedPosts() async {
|
||||
final client = ServiceFinder.configureClient('interactive');
|
||||
final client = await ServiceFinder.configureClient('interactive');
|
||||
final resp = await client.get('/users/${widget.name}/pin');
|
||||
if (resp.statusCode != 200) {
|
||||
context.showErrorDialog(resp.bodyString).then((_) {
|
||||
@@ -95,7 +95,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
_relationshipProvider = Get.find();
|
||||
_postController = PostListController(author: widget.name);
|
||||
_albumPagingController.addPageRequestListener((pageKey) async {
|
||||
final client = ServiceFinder.configureClient('files');
|
||||
final client = await ServiceFinder.configureClient('files');
|
||||
final resp = await client.get(
|
||||
'/attachments?take=10&offset=$pageKey&author=${widget.name}&original=true',
|
||||
);
|
||||
|
||||
@@ -48,7 +48,7 @@ class _StickerScreenState extends State<StickerScreen> {
|
||||
);
|
||||
if (confirm != true) return false;
|
||||
|
||||
final client = auth.configureClient('files');
|
||||
final client = await auth.configureClient('files');
|
||||
final resp = await client.delete('/stickers/${item.id}');
|
||||
|
||||
return resp.statusCode == 200;
|
||||
@@ -107,7 +107,7 @@ class _StickerScreenState extends State<StickerScreen> {
|
||||
final AuthProvider auth = Get.find();
|
||||
final name = auth.userProfile.value!['name'];
|
||||
_pagingController.addPageRequestListener((pageKey) async {
|
||||
final client = ServiceFinder.configureClient('files');
|
||||
final client = await ServiceFinder.configureClient('files');
|
||||
final resp = await client.get(
|
||||
'/stickers/manifest?take=10&offset=$pageKey&author=$name',
|
||||
);
|
||||
|
||||
@@ -1,28 +1,46 @@
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:protocol_handler/protocol_handler.dart';
|
||||
import 'package:solian/background.dart';
|
||||
import 'package:solian/exceptions/request.dart';
|
||||
import 'package:solian/exts.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/models/auth.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/services.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:solian/widgets/sized_container.dart';
|
||||
|
||||
class SignInPopup extends StatefulWidget {
|
||||
const SignInPopup({super.key});
|
||||
class SignInScreen extends StatefulWidget {
|
||||
const SignInScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SignInPopup> createState() => _SignInPopupState();
|
||||
State<SignInScreen> createState() => _SignInScreenState();
|
||||
}
|
||||
|
||||
class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
class _SignInScreenState extends State<SignInScreen> {
|
||||
bool _isBusy = false;
|
||||
|
||||
AuthTicket? _currentTicket;
|
||||
|
||||
List<AuthFactor>? _factors;
|
||||
int? _factorPicked;
|
||||
int? _factorPickedType;
|
||||
|
||||
int _period = 0;
|
||||
|
||||
final _usernameController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
|
||||
void requestResetPassword() async {
|
||||
final Map<int, (String label, IconData icon, bool isOtp)> _factorLabelMap = {
|
||||
0: ('authFactorPassword'.tr, Icons.password, false),
|
||||
1: ('authFactorEmail'.tr, Icons.email, true),
|
||||
};
|
||||
|
||||
Color get _unFocusColor =>
|
||||
Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
|
||||
|
||||
void _requestResetPassword() async {
|
||||
final username = _usernameController.value.text;
|
||||
if (username.isEmpty) {
|
||||
context.showErrorDialog('signinResetPasswordHint'.tr);
|
||||
@@ -31,7 +49,7 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = ServiceFinder.configureClient('auth');
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
final lookupResp = await client.get('/users/lookup?probe=$username');
|
||||
if (lookupResp.statusCode != 200) {
|
||||
context.showErrorDialog(lookupResp.bodyString);
|
||||
@@ -52,154 +70,383 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
context.showModalDialog('done'.tr, 'signinResetPasswordSent'.tr);
|
||||
}
|
||||
|
||||
void performAction() async {
|
||||
final AuthProvider auth = Get.find();
|
||||
|
||||
void _performNewTicket() async {
|
||||
final username = _usernameController.value.text;
|
||||
final password = _passwordController.value.text;
|
||||
if (username.isEmpty || password.isEmpty) return;
|
||||
if (username.isEmpty) return;
|
||||
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
try {
|
||||
await auth.signin(context, username, password);
|
||||
await Future.delayed(const Duration(milliseconds: 250), () async {
|
||||
await auth.refreshAuthorizeStatus();
|
||||
await auth.refreshUserProfile();
|
||||
// Create ticket
|
||||
final resp = await client.post('/auth', {
|
||||
'username': username,
|
||||
});
|
||||
} on RiskyAuthenticateException catch (e) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('riskDetection'.tr),
|
||||
content: Text('signinRiskDetected'.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('next'.tr),
|
||||
onPressed: () {
|
||||
const redirect = 'solink://auth?status=done';
|
||||
launchUrlString(
|
||||
ServiceFinder.buildUrl('capital',
|
||||
'/auth/mfa?redirect_uri=$redirect&ticketId=${e.ticketId}'),
|
||||
mode: LaunchMode.inAppWebView,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
return;
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
} else {
|
||||
final result = AuthResult.fromJson(resp.body);
|
||||
_currentTicket = result.ticket;
|
||||
}
|
||||
|
||||
// Pull factors
|
||||
final factorResp = await client.get('/auth/factors',
|
||||
query: {'ticketId': _currentTicket!.id.toString()});
|
||||
if (factorResp.statusCode != 200) {
|
||||
throw RequestException(factorResp);
|
||||
} else {
|
||||
final result = List<AuthFactor>.from(
|
||||
factorResp.body.map((x) => AuthFactor.fromJson(x)),
|
||||
);
|
||||
_factors = result;
|
||||
}
|
||||
|
||||
setState(() => _period++);
|
||||
} catch (e) {
|
||||
context.showErrorDialog(e);
|
||||
return;
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
}
|
||||
|
||||
Get.find<WebSocketProvider>().registerPushNotifications();
|
||||
|
||||
Navigator.pop(context, true);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
protocolHandler.addListener(this);
|
||||
super.initState();
|
||||
void _performGetFactorCode() async {
|
||||
if (_factorPicked == null) return;
|
||||
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
try {
|
||||
// Request one-time-password code
|
||||
final resp = await client.post('/auth/factors/$_factorPicked', {});
|
||||
if (resp.statusCode != 200 && resp.statusCode != 204) {
|
||||
throw RequestException(resp);
|
||||
} else {
|
||||
_factorPickedType = _factors!
|
||||
.where(
|
||||
(x) => x.id == _factorPicked,
|
||||
)
|
||||
.first
|
||||
.type;
|
||||
}
|
||||
|
||||
setState(() => _period++);
|
||||
} catch (e) {
|
||||
context.showErrorDialog(e);
|
||||
return;
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
protocolHandler.removeListener(this);
|
||||
super.dispose();
|
||||
void _performCheckTicket() async {
|
||||
final AuthProvider auth = Get.find();
|
||||
|
||||
final password = _passwordController.value.text;
|
||||
if (password.isEmpty) return;
|
||||
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
try {
|
||||
// Check ticket
|
||||
final resp = await client.patch('/auth', {
|
||||
'ticket_id': _currentTicket!.id,
|
||||
'factor_id': _factorPicked!,
|
||||
'code': password,
|
||||
});
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
}
|
||||
|
||||
final result = AuthResult.fromJson(resp.body);
|
||||
_currentTicket = result.ticket;
|
||||
|
||||
// Finish sign in if possible
|
||||
if (result.isFinished) {
|
||||
await auth.signin(context, _currentTicket!);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 250), () async {
|
||||
await auth.refreshAuthorizeStatus();
|
||||
await auth.refreshUserProfile();
|
||||
|
||||
Get.find<WebSocketProvider>().registerPushNotifications();
|
||||
autoConfigureBackgroundNotificationService();
|
||||
autoStartBackgroundNotificationService();
|
||||
|
||||
Navigator.pop(context, true);
|
||||
});
|
||||
} else {
|
||||
// Skip the first step
|
||||
_factorPicked = null;
|
||||
_factorPickedType = null;
|
||||
setState(() => _period += 2);
|
||||
}
|
||||
} catch (e) {
|
||||
context.showErrorDialog(e);
|
||||
return;
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onProtocolUrlReceived(String url) {
|
||||
final uri = url.replaceFirst('solink://', '');
|
||||
if (uri == 'auth?status=done') {
|
||||
closeInAppWebView();
|
||||
performAction();
|
||||
void _previousStep() {
|
||||
assert(_period > 0);
|
||||
switch (_period % 3) {
|
||||
case 1:
|
||||
_currentTicket = null;
|
||||
_factors = null;
|
||||
_factorPicked = null;
|
||||
case 2:
|
||||
_passwordController.clear();
|
||||
_factorPickedType = null;
|
||||
default:
|
||||
setState(() => _period--);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.9,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.6,
|
||||
constraints: const BoxConstraints(maxWidth: 360),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: Image.asset('assets/logo.png', width: 64, height: 64),
|
||||
).paddingOnly(bottom: 4),
|
||||
Text(
|
||||
'signinGreeting'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
).paddingOnly(left: 4, bottom: 16),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _usernameController,
|
||||
autofillHints: const [AutofillHints.username],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'username'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const Gap(12),
|
||||
TextField(
|
||||
obscureText: true,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
controller: _passwordController,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'password'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onSubmitted: (_) => performAction(),
|
||||
),
|
||||
const Gap(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: CenteredContainer(
|
||||
maxWidth: 360,
|
||||
child: PageTransitionSwitcher(
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> primaryAnimation,
|
||||
Animation<double> secondaryAnimation,
|
||||
) {
|
||||
return SharedAxisTransition(
|
||||
animation: primaryAnimation,
|
||||
secondaryAnimation: secondaryAnimation,
|
||||
transitionType: SharedAxisTransitionType.horizontal,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: switch (_period % 3) {
|
||||
1 => Column(
|
||||
key: const ValueKey<int>(1),
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: _isBusy ? null : () => requestResetPassword(),
|
||||
style: TextButton.styleFrom(foregroundColor: Colors.grey),
|
||||
child: Text('forgotPassword'.tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _isBusy ? null : () => performAction(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('next'.tr),
|
||||
const Icon(Icons.chevron_right),
|
||||
],
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child:
|
||||
Image.asset('assets/logo.png', width: 64, height: 64),
|
||||
).paddingOnly(bottom: 8, left: 4),
|
||||
Text(
|
||||
'signinPickFactor'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
).paddingOnly(left: 4, bottom: 16),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Column(
|
||||
children: _factors
|
||||
?.map(
|
||||
(x) => CheckboxListTile(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8),
|
||||
),
|
||||
),
|
||||
secondary: Icon(
|
||||
_factorLabelMap[x.type]?.$2 ??
|
||||
Icons.question_mark,
|
||||
),
|
||||
title: Text(
|
||||
_factorLabelMap[x.type]?.$1 ?? 'unknown'.tr,
|
||||
),
|
||||
enabled: !_currentTicket!.factorTrail
|
||||
.contains(x.id),
|
||||
value: _factorPicked == x.id,
|
||||
onChanged: (value) {
|
||||
if (value == true) {
|
||||
setState(() => _factorPicked = x.id);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList() ??
|
||||
List.empty(),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'signinMultiFactor'.trParams(
|
||||
{'n': _currentTicket!.stepRemain.toString()},
|
||||
),
|
||||
style: TextStyle(color: _unFocusColor, fontSize: 12),
|
||||
).paddingOnly(left: 16, right: 16),
|
||||
const Gap(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: (_isBusy || _period > 1)
|
||||
? null
|
||||
: () => _previousStep(),
|
||||
style:
|
||||
TextButton.styleFrom(foregroundColor: Colors.grey),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.chevron_left),
|
||||
Text('prev'.tr),
|
||||
],
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed:
|
||||
_isBusy ? null : () => _performGetFactorCode(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('next'.tr),
|
||||
const Icon(Icons.chevron_right),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
2 => Column(
|
||||
key: const ValueKey<int>(2),
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child:
|
||||
Image.asset('assets/logo.png', width: 64, height: 64),
|
||||
).paddingOnly(bottom: 8, left: 4),
|
||||
Text(
|
||||
'signinEnterPassword'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
).paddingOnly(left: 4, bottom: 16),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
autofillHints: [
|
||||
(_factorLabelMap[_factorPickedType]?.$3 ?? true)
|
||||
? AutofillHints.password
|
||||
: AutofillHints.oneTimeCode
|
||||
],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText:
|
||||
(_factorLabelMap[_factorPickedType]?.$3 ?? true)
|
||||
? 'passwordOneTime'.tr
|
||||
: 'password'.tr,
|
||||
helperText:
|
||||
(_factorLabelMap[_factorPickedType]?.$3 ?? true)
|
||||
? 'passwordOneTimeInputHint'.tr
|
||||
: 'passwordInputHint'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onSubmitted: _isBusy ? null : (_) => _performCheckTicket(),
|
||||
),
|
||||
const Gap(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: _isBusy ? null : () => _previousStep(),
|
||||
style:
|
||||
TextButton.styleFrom(foregroundColor: Colors.grey),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.chevron_left),
|
||||
Text('prev'.tr),
|
||||
],
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _isBusy ? null : () => _performCheckTicket(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('next'.tr),
|
||||
const Icon(Icons.chevron_right),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
_ => Column(
|
||||
key: const ValueKey<int>(0),
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child:
|
||||
Image.asset('assets/logo.png', width: 64, height: 64),
|
||||
).paddingOnly(bottom: 8, left: 4),
|
||||
Text(
|
||||
'signinGreeting'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
).paddingOnly(left: 4, bottom: 16),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _usernameController,
|
||||
autofillHints: const [AutofillHints.username],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'username'.tr,
|
||||
helperText: 'usernameInputHint'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onSubmitted: _isBusy ? null : (_) => _performNewTicket(),
|
||||
),
|
||||
const Gap(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed:
|
||||
_isBusy ? null : () => _requestResetPassword(),
|
||||
style:
|
||||
TextButton.styleFrom(foregroundColor: Colors.grey),
|
||||
child: Text('forgotPassword'.tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _isBusy ? null : () => _performNewTicket(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('next'.tr),
|
||||
const Icon(Icons.chevron_right),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,15 +3,16 @@ import 'package:gap/gap.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:solian/exts.dart';
|
||||
import 'package:solian/services.dart';
|
||||
import 'package:solian/widgets/sized_container.dart';
|
||||
|
||||
class SignUpPopup extends StatefulWidget {
|
||||
const SignUpPopup({super.key});
|
||||
class SignUpScreen extends StatefulWidget {
|
||||
const SignUpScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SignUpPopup> createState() => _SignUpPopupState();
|
||||
State<SignUpScreen> createState() => _SignUpScreenState();
|
||||
}
|
||||
|
||||
class _SignUpPopupState extends State<SignUpPopup> {
|
||||
class _SignUpScreenState extends State<SignUpScreen> {
|
||||
final _emailController = TextEditingController();
|
||||
final _usernameController = TextEditingController();
|
||||
final _nicknameController = TextEditingController();
|
||||
@@ -27,7 +28,7 @@ class _SignUpPopupState extends State<SignUpPopup> {
|
||||
nickname.isEmpty ||
|
||||
password.isEmpty) return;
|
||||
|
||||
final client = ServiceFinder.configureClient('auth');
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
|
||||
final resp = await client.post('/users', {
|
||||
'name': username,
|
||||
@@ -61,100 +62,97 @@ class _SignUpPopupState extends State<SignUpPopup> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.9,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.6,
|
||||
constraints: const BoxConstraints(maxWidth: 360),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: Image.asset('assets/logo.png', width: 64, height: 64),
|
||||
).paddingOnly(bottom: 4),
|
||||
Text(
|
||||
'signupGreeting'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
).paddingOnly(left: 4, bottom: 16),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _usernameController,
|
||||
autofillHints: const [AutofillHints.username],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'username'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
return Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: CenteredContainer(
|
||||
maxWidth: 360,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: Image.asset('assets/logo.png', width: 64, height: 64),
|
||||
).paddingOnly(bottom: 8, left: 4),
|
||||
Text(
|
||||
'signupGreeting'.tr,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
const Gap(12),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _nicknameController,
|
||||
autofillHints: const [AutofillHints.nickname],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'nickname'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
).paddingOnly(left: 4, bottom: 16),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _usernameController,
|
||||
autofillHints: const [AutofillHints.username],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'username'.tr,
|
||||
),
|
||||
const Gap(12),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _emailController,
|
||||
autofillHints: const [AutofillHints.email],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'email'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const Gap(12),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _nicknameController,
|
||||
autofillHints: const [AutofillHints.nickname],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'nickname'.tr,
|
||||
),
|
||||
const Gap(12),
|
||||
TextField(
|
||||
obscureText: true,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
controller: _passwordController,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'password'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onSubmitted: (_) => performAction(context),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const Gap(12),
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _emailController,
|
||||
autofillHints: const [AutofillHints.email],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'email'.tr,
|
||||
),
|
||||
const Gap(16),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: TextButton(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('next'.tr),
|
||||
const Icon(Icons.chevron_right),
|
||||
],
|
||||
),
|
||||
onPressed: () => performAction(context),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
const Gap(12),
|
||||
TextField(
|
||||
obscureText: true,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
controller: _passwordController,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'password'.tr,
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onSubmitted: (_) => performAction(context),
|
||||
),
|
||||
const Gap(16),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: TextButton(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('next'.tr),
|
||||
const Icon(Icons.chevron_right),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
onPressed: () => performAction(context),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -97,7 +97,6 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
|
||||
setState(() => _ongoingCall = Call.fromJson(resp.body));
|
||||
}
|
||||
} catch (e) {
|
||||
print((e as dynamic).stackTrace);
|
||||
context.showErrorDialog(e);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client
|
||||
.put('/channels/${widget.realm}/${widget.channel.alias}/members/me', {
|
||||
|
||||
@@ -102,7 +102,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
body: Obx(() {
|
||||
if (auth.isAuthorized.isFalse) {
|
||||
return SigninRequiredOverlay(
|
||||
onSignedIn: () => _channels.refreshAvailableChannel(),
|
||||
onDone: () => _channels.refreshAvailableChannel(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class _FeedScreenState extends State<FeedScreen>
|
||||
);
|
||||
} else {
|
||||
return SigninRequiredOverlay(
|
||||
onSignedIn: () => _postController.reloadAllOver(),
|
||||
onDone: () => _postController.reloadAllOver(),
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -75,7 +75,7 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('interactive');
|
||||
final client = await auth.configureClient('interactive');
|
||||
|
||||
Response resp;
|
||||
if (widget.edit != null) {
|
||||
|
||||
@@ -84,7 +84,7 @@ class _RealmListScreenState extends State<RealmListScreen> {
|
||||
body: Obx(() {
|
||||
if (auth.isAuthorized.isFalse) {
|
||||
return SigninRequiredOverlay(
|
||||
onSignedIn: () => _getRealms(),
|
||||
onDone: () => _getRealms(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class _RealmOrganizeScreenState extends State<RealmOrganizeScreen> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final payload = {
|
||||
'alias': _aliasController.value.text.toLowerCase(),
|
||||
|
||||
@@ -3,6 +3,8 @@ import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:solian/exts.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
import 'package:solian/providers/database/database.dart';
|
||||
import 'package:solian/providers/theme_switcher.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/theme.dart';
|
||||
@@ -15,7 +17,7 @@ class SettingScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SettingScreenState extends State<SettingScreen> {
|
||||
late final SharedPreferences _prefs;
|
||||
SharedPreferences? _prefs;
|
||||
|
||||
Widget _buildCaptionHeader(String title) {
|
||||
return Container(
|
||||
@@ -41,7 +43,7 @@ class _SettingScreenState extends State<SettingScreen> {
|
||||
seedColor: color,
|
||||
),
|
||||
);
|
||||
_prefs.setInt('global_theme_color', color.value);
|
||||
_prefs?.setInt('global_theme_color', color.value);
|
||||
context.clearSnackbar();
|
||||
context.showSnackbar('themeColorApplied'.tr);
|
||||
},
|
||||
@@ -61,6 +63,9 @@ class _SettingScreenState extends State<SettingScreen> {
|
||||
super.initState();
|
||||
SharedPreferences.getInstance().then((inst) {
|
||||
_prefs = inst;
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -80,7 +85,60 @@ class _SettingScreenState extends State<SettingScreen> {
|
||||
.toList(),
|
||||
).paddingSymmetric(horizontal: 12, vertical: 8),
|
||||
),
|
||||
_buildCaptionHeader('notification'.tr),
|
||||
Tooltip(
|
||||
message: 'settingsNotificationBgServiceDesc'.tr,
|
||||
child: CheckboxListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 22),
|
||||
secondary: const Icon(Icons.system_security_update_warning),
|
||||
enabled: PlatformInfo.isAndroid,
|
||||
title: Text('settingsNotificationBgService'.tr),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('holdToSeeDetail'.tr),
|
||||
Text(
|
||||
'needRestartToApply'.tr,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
)
|
||||
],
|
||||
),
|
||||
value:
|
||||
_prefs?.getBool('service_background_notification') ?? false,
|
||||
onChanged: (value) {
|
||||
_prefs
|
||||
?.setBool('service_background_notification', value ?? false)
|
||||
.then((_) {
|
||||
setState(() {});
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
_buildCaptionHeader('more'.tr),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.delete_sweep),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
subtitle: FutureBuilder(
|
||||
future: AppDatabase.getDatabaseSize(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return Text('localDatabaseSize'.trParams(
|
||||
{'size': 'unknown'.tr},
|
||||
));
|
||||
}
|
||||
return Text('localDatabaseSize'.trParams(
|
||||
{'size': snapshot.data!.formatBytes()},
|
||||
));
|
||||
},
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 22),
|
||||
title: Text('localDatabaseWipe'.tr),
|
||||
onTap: () {
|
||||
AppDatabase.removeDatabase().then((_) {
|
||||
setState(() {});
|
||||
});
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
@@ -90,15 +148,6 @@ class _SettingScreenState extends State<SettingScreen> {
|
||||
AppRouter.instance.pushNamed('about');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.delete_sweep),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 22),
|
||||
title: Text('messageHistoryWipe'.tr),
|
||||
onTap: () {
|
||||
// TODO Wipe message history
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,28 +1,58 @@
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
|
||||
abstract class ServiceFinder {
|
||||
static const bool devFlag = false;
|
||||
|
||||
static const String dealerUrl =
|
||||
devFlag ? 'http://localhost:8442' : 'https://api.sn.solsynth.dev';
|
||||
static const String capitalUrl =
|
||||
devFlag ? 'http://localhost:8444' : 'https://solsynth.dev';
|
||||
|
||||
static String buildUrl(String serviceName, String? append) {
|
||||
append ??= '';
|
||||
if (serviceName == 'dealer') {
|
||||
return '$dealerUrl$append';
|
||||
} else if (serviceName == 'capital') {
|
||||
return '$capitalUrl$append';
|
||||
}
|
||||
return '$dealerUrl/cgi/$serviceName$append';
|
||||
}
|
||||
|
||||
static GetConnect configureClient(String serviceName,
|
||||
{timeout = const Duration(seconds: 5)}) {
|
||||
static Future<String> getUserAgent() async {
|
||||
final String platformInfo;
|
||||
if (PlatformInfo.isAndroid) {
|
||||
final deviceInfo = await DeviceInfoPlugin().androidInfo;
|
||||
platformInfo =
|
||||
'Android; ${deviceInfo.brand} ${deviceInfo.model}; ${deviceInfo.id}';
|
||||
} else if (PlatformInfo.isIOS) {
|
||||
final deviceInfo = await DeviceInfoPlugin().iosInfo;
|
||||
platformInfo = 'iOS; ${deviceInfo.model}; ${deviceInfo.name}';
|
||||
} else if (PlatformInfo.isMacOS) {
|
||||
final deviceInfo = await DeviceInfoPlugin().macOsInfo;
|
||||
platformInfo = 'MacOS; ${deviceInfo.model}; ${deviceInfo.hostName}';
|
||||
} else if (PlatformInfo.isWindows) {
|
||||
final deviceInfo = await DeviceInfoPlugin().windowsInfo;
|
||||
platformInfo =
|
||||
'Windows NT; ${deviceInfo.productName}; ${deviceInfo.computerName}';
|
||||
} else if (PlatformInfo.isLinux) {
|
||||
final deviceInfo = await DeviceInfoPlugin().linuxInfo;
|
||||
platformInfo = 'Linux; ${deviceInfo.prettyName}';
|
||||
} else if (PlatformInfo.isWeb) {
|
||||
final deviceInfo = await DeviceInfoPlugin().webBrowserInfo;
|
||||
platformInfo = 'Web; ${deviceInfo.vendor}';
|
||||
} else {
|
||||
platformInfo = 'Unknown';
|
||||
}
|
||||
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
return 'Solian/${packageInfo.version}+${packageInfo.buildNumber} ($platformInfo)';
|
||||
}
|
||||
|
||||
static Future<GetConnect> configureClient(String serviceName,
|
||||
{timeout = const Duration(seconds: 5)}) async {
|
||||
final client = GetConnect(
|
||||
timeout: timeout,
|
||||
userAgent: 'Solian/1.1',
|
||||
userAgent: await getUserAgent(),
|
||||
sendUserAgent: true,
|
||||
);
|
||||
client.httpClient.baseUrl = buildUrl(serviceName, null);
|
||||
|
||||
@@ -24,6 +24,8 @@ class TitleShell extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(state != null || title != null);
|
||||
|
||||
return Scaffold(
|
||||
appBar: showAppBar
|
||||
? AppBar(
|
||||
|
||||
@@ -26,7 +26,7 @@ class _AccountProfilePopupState extends State<AccountProfilePopup> {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
try {
|
||||
final client = ServiceFinder.configureClient('auth');
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
final resp = await client.get('/users/${widget.name}');
|
||||
if (resp.statusCode == 200) {
|
||||
setState(() {
|
||||
|
||||
@@ -36,16 +36,13 @@ class _AccountSelectorState extends State<AccountSelector> {
|
||||
|
||||
_revertSelectedUsers() async {
|
||||
if (widget.initialSelection?.isEmpty ?? true) return;
|
||||
final client = ServiceFinder.configureClient('auth');
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
final idQuery = widget.initialSelection!.join(',');
|
||||
final resp = await client.get('/users?id=$idQuery');
|
||||
|
||||
setState(() {
|
||||
_selectedUsers.addAll(
|
||||
resp.body
|
||||
.map((e) => Account.fromJson(e))
|
||||
.toList()
|
||||
.cast<Account>(),
|
||||
resp.body.map((e) => Account.fromJson(e)).toList().cast<Account>(),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -73,7 +70,7 @@ class _AccountSelectorState extends State<AccountSelector> {
|
||||
|
||||
if (_probeController.text.isEmpty) return;
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
final resp = await client.get(
|
||||
'/users/search?probe=${_probeController.text}',
|
||||
);
|
||||
@@ -156,7 +153,8 @@ class _AccountSelectorState extends State<AccountSelector> {
|
||||
}
|
||||
|
||||
setState(() {
|
||||
final idx = _selectedUsers.indexWhere((x) => x.id == element.id);
|
||||
final idx = _selectedUsers
|
||||
.indexWhere((x) => x.id == element.id);
|
||||
if (idx != -1) {
|
||||
_selectedUsers.removeAt(idx);
|
||||
} else {
|
||||
|
||||
@@ -1,49 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:solian/screens/auth/signin.dart';
|
||||
import 'package:solian/router.dart';
|
||||
import 'package:solian/widgets/sized_container.dart';
|
||||
|
||||
class SigninRequiredOverlay extends StatelessWidget {
|
||||
final Function onSignedIn;
|
||||
final Function onDone;
|
||||
|
||||
const SigninRequiredOverlay({super.key, required this.onSignedIn});
|
||||
const SigninRequiredOverlay({super.key, required this.onDone});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
child: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 280),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.login,
|
||||
size: 48,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'signinRequired'.tr,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
'signinRequiredHint'.tr,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: CenteredContainer(
|
||||
maxWidth: 280,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.login,
|
||||
size: 48,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'signinRequired'.tr,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
'signinRequiredHint'.tr,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (context) => const SignInPopup(),
|
||||
).then((value) {
|
||||
if (value != null) onSignedIn();
|
||||
AppRouter.instance.pushNamed('signin').then((value) {
|
||||
if (value != null) onDone();
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:desktop_drop/desktop_drop.dart';
|
||||
import 'package:dismissible_page/dismissible_page.dart';
|
||||
@@ -209,25 +208,6 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
});
|
||||
}
|
||||
|
||||
String _formatBytes(int bytes, {int decimals = 2}) {
|
||||
if (bytes == 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(bytes) / math.log(k)).floor().toInt();
|
||||
return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
||||
}
|
||||
|
||||
void _revertMetadataList() {
|
||||
final AttachmentProvider attach = Get.find();
|
||||
|
||||
@@ -332,7 +312,9 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
}
|
||||
|
||||
Widget _buildQueueEntry(AttachmentUploadTask element, int index) {
|
||||
final extName = extension(element.file.path).substring(1);
|
||||
final extName = element.file.name.contains('.')
|
||||
? extension(element.file.name).substring(1)
|
||||
: '';
|
||||
final canBeCrop = ['png', 'jpg', 'jpeg', 'gif'].contains(extName);
|
||||
|
||||
return Container(
|
||||
@@ -367,7 +349,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Text(
|
||||
_formatBytes(snapshot.data!),
|
||||
snapshot.data!.formatBytes(),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
);
|
||||
},
|
||||
@@ -502,7 +484,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${fileType[0].toUpperCase()}${fileType.substring(1)} · ${_formatBytes(element.size)}',
|
||||
'${fileType[0].toUpperCase()}${fileType.substring(1)} · ${element.size.formatBytes()}',
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -38,25 +38,6 @@ class _AttachmentFullScreenState extends State<AttachmentFullScreen> {
|
||||
Color get _unFocusColor =>
|
||||
Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
|
||||
|
||||
String _formatBytes(int bytes, {int decimals = 2}) {
|
||||
if (bytes == 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(bytes) / math.log(k)).floor().toInt();
|
||||
return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
||||
}
|
||||
|
||||
double _getRatio() {
|
||||
final value = widget.item.metadata?['ratio'];
|
||||
if (value == null) return 1;
|
||||
@@ -274,7 +255,7 @@ class _AttachmentFullScreenState extends State<AttachmentFullScreen> {
|
||||
style: metaTextStyle,
|
||||
),
|
||||
Text(
|
||||
_formatBytes(widget.item.size),
|
||||
widget.item.size.formatBytes(),
|
||||
style: metaTextStyle,
|
||||
),
|
||||
Text(
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:get/get.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:solian/exts.dart';
|
||||
import 'package:solian/models/attachment.dart';
|
||||
import 'package:solian/providers/durations.dart';
|
||||
import 'package:solian/services.dart';
|
||||
@@ -377,25 +378,6 @@ class _AttachmentItemAudioState extends State<_AttachmentItemAudio> {
|
||||
);
|
||||
}
|
||||
|
||||
String _formatBytes(int bytes, {int decimals = 2}) {
|
||||
if (bytes == 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(bytes) / math.log(k)).floor().toInt();
|
||||
return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -471,7 +453,7 @@ class _AttachmentItemAudioState extends State<_AttachmentItemAudio> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_formatBytes(widget.item.size),
|
||||
widget.item.size.formatBytes(),
|
||||
style: GoogleFonts.robotoMono(
|
||||
fontSize: 12,
|
||||
shadows: labelShadows,
|
||||
|
||||
@@ -29,10 +29,10 @@ class _ChannelDeletionDialogState extends State<ChannelDeletionDialog> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client
|
||||
.delete('/channels/${widget.realm}/${widget.channel.id}');
|
||||
final resp =
|
||||
await client.delete('/channels/${widget.realm}/${widget.channel.id}');
|
||||
if (resp.statusCode != 200) {
|
||||
context.showErrorDialog(resp.bodyString);
|
||||
} else if (Navigator.canPop(context)) {
|
||||
@@ -48,7 +48,7 @@ class _ChannelDeletionDialogState extends State<ChannelDeletionDialog> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.delete(
|
||||
'/channels/${widget.realm}/${widget.channel.alias}/members/me',
|
||||
@@ -69,11 +69,11 @@ class _ChannelDeletionDialogState extends State<ChannelDeletionDialog> {
|
||||
? 'channelDeletionConfirm'.tr
|
||||
: 'channelLeaveConfirm'.tr),
|
||||
content: Text(
|
||||
widget.isOwned ?
|
||||
'channelDeletionConfirmCaption'
|
||||
.trParams({'channel': '#${widget.channel.alias}'}) :
|
||||
'channelLeaveConfirmCaption'
|
||||
.trParams({'channel': '#${widget.channel.alias}'}),
|
||||
widget.isOwned
|
||||
? 'channelDeletionConfirmCaption'
|
||||
.trParams({'channel': '#${widget.channel.alias}'})
|
||||
: 'channelLeaveConfirmCaption'
|
||||
.trParams({'channel': '#${widget.channel.alias}'}),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
|
||||
@@ -39,7 +39,7 @@ class _ChannelMemberListPopupState extends State<ChannelMemberListPopup> {
|
||||
void getMembers() async {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = ServiceFinder.configureClient('messaging');
|
||||
final client = await ServiceFinder.configureClient('messaging');
|
||||
|
||||
final resp = await client
|
||||
.get('/channels/${widget.realm}/${widget.channel.alias}/members');
|
||||
@@ -75,7 +75,7 @@ class _ChannelMemberListPopupState extends State<ChannelMemberListPopup> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.post(
|
||||
'/channels/${widget.realm}/${widget.channel.alias}/members',
|
||||
@@ -96,7 +96,7 @@ class _ChannelMemberListPopupState extends State<ChannelMemberListPopup> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.request(
|
||||
'/channels/${widget.realm}/${widget.channel.alias}/members',
|
||||
|
||||
@@ -33,7 +33,7 @@ class _ChatCallButtonState extends State<ChatCallButton> {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return;
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
@@ -57,7 +57,7 @@ class _ChatCallButtonState extends State<ChatCallButton> {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return;
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class _ChatEventDeletionDialogState extends State<ChatEventDeletionDialog> {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return;
|
||||
|
||||
final client = auth.configureClient('messaging');
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
||||
final mentionedUserNames = _findMentionedUsers(_textController.text);
|
||||
final mentionedUserIds = List<int>.empty(growable: true);
|
||||
|
||||
var client = auth.configureClient('auth');
|
||||
var client = await auth.configureClient('auth');
|
||||
if (mentionedUserNames.isNotEmpty) {
|
||||
resp = await client.get('/users?name=${mentionedUserNames.join(',')}');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -131,7 +131,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
||||
}
|
||||
}
|
||||
|
||||
client = auth.configureClient('messaging');
|
||||
client = await auth.configureClient('messaging');
|
||||
|
||||
if (_textController.text.trim().isEmpty && _attachments.isEmpty) return;
|
||||
|
||||
@@ -432,7 +432,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
||||
final userSearch = userMatch[1]!.toLowerCase();
|
||||
final AuthProvider auth = Get.find();
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
final resp = await client.get(
|
||||
'/users/search?probe=$userSearch',
|
||||
);
|
||||
|
||||
@@ -138,7 +138,14 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer>
|
||||
Builder(
|
||||
builder: (context) {
|
||||
if (_accountStatus == null) {
|
||||
return Text('loading'.tr).paddingOnly(left: 16);
|
||||
return Text(
|
||||
'loading'.tr,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.fade,
|
||||
style: TextStyle(
|
||||
color: _unFocusColor,
|
||||
),
|
||||
).paddingOnly(left: 16);
|
||||
}
|
||||
final info = StatusProvider.determineStatus(
|
||||
_accountStatus!,
|
||||
@@ -204,7 +211,8 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getStatus();
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.value) _getStatus();
|
||||
Future.delayed(Duration.zero, () => _autoResize());
|
||||
_drawerAnimationController.addListener(() {
|
||||
if (_drawerAnimation.value > 180 && _isCollapsed) {
|
||||
@@ -273,6 +281,9 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer>
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: AppNavigationRegion(
|
||||
isCollapsed: _isCollapsed,
|
||||
onSelected: () {
|
||||
_closeDrawer();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -10,10 +10,12 @@ import 'package:solian/widgets/channel/channel_list.dart';
|
||||
|
||||
class AppNavigationRegion extends StatefulWidget {
|
||||
final bool isCollapsed;
|
||||
final Function onSelected;
|
||||
|
||||
const AppNavigationRegion({
|
||||
super.key,
|
||||
this.isCollapsed = false,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -204,6 +206,7 @@ class _AppNavigationRegionState extends State<AppNavigationRegion> {
|
||||
isCollapsed: widget.isCollapsed,
|
||||
selfId: auth.userProfile.value!['id'],
|
||||
noCategory: true,
|
||||
onSelected: (_) => widget.onSelected(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -35,7 +35,7 @@ class _TagsFieldState extends State<TagsField> {
|
||||
Future<List<String>?> _searchTags(String probe) async {
|
||||
_currentSearchProbe = probe;
|
||||
|
||||
final client = ServiceFinder.configureClient('interactive');
|
||||
final client = await ServiceFinder.configureClient('interactive');
|
||||
final resp = await client.get(
|
||||
'/tags?take=10&probe=$_currentSearchProbe',
|
||||
);
|
||||
|
||||
@@ -192,7 +192,7 @@ class _PostActionState extends State<PostAction> {
|
||||
: 'unpinPost'.tr,
|
||||
),
|
||||
onTap: () async {
|
||||
final client = Get.find<AuthProvider>()
|
||||
final client = await Get.find<AuthProvider>()
|
||||
.configureClient('interactive');
|
||||
await client.post('/posts/${widget.item.id}/pin', {});
|
||||
Navigator.pop(context, true);
|
||||
@@ -254,7 +254,7 @@ class _PostDeletionDialogState extends State<PostDeletionDialog> {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) return;
|
||||
|
||||
final client = auth.configureClient('interactive');
|
||||
final client = await auth.configureClient('interactive');
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
final resp = await client.delete('/posts/${widget.item.id}');
|
||||
|
||||
@@ -49,7 +49,7 @@ class _PostQuickActionState extends State<PostQuickAction> {
|
||||
if (_isSubmitting) return;
|
||||
if (auth.isAuthorized.isFalse) return;
|
||||
|
||||
final client = auth.configureClient('interactive');
|
||||
final client = await auth.configureClient('interactive');
|
||||
|
||||
setState(() => _isSubmitting = true);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class _RealmDeletionDialogState extends State<RealmDeletionDialog> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.delete('/realms/${widget.realm.id}');
|
||||
if (resp.statusCode != 200) {
|
||||
@@ -45,10 +45,9 @@ class _RealmDeletionDialogState extends State<RealmDeletionDialog> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp =
|
||||
await client.delete('/realms/${widget.realm.id}/members/me');
|
||||
final resp = await client.delete('/realms/${widget.realm.id}/members/me');
|
||||
if (resp.statusCode != 200) {
|
||||
context.showErrorDialog(resp.bodyString);
|
||||
} else if (Navigator.canPop(context)) {
|
||||
|
||||
@@ -37,7 +37,7 @@ class _RealmMemberListPopupState extends State<RealmMemberListPopup> {
|
||||
void getMembers() async {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = ServiceFinder.configureClient('auth');
|
||||
final client = await ServiceFinder.configureClient('auth');
|
||||
|
||||
final resp = await client.get('/realms/${widget.realm.alias}/members');
|
||||
if (resp.statusCode == 200) {
|
||||
@@ -72,7 +72,7 @@ class _RealmMemberListPopupState extends State<RealmMemberListPopup> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.post(
|
||||
'/realms/${widget.realm.alias}/members',
|
||||
@@ -93,7 +93,7 @@ class _RealmMemberListPopupState extends State<RealmMemberListPopup> {
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final client = auth.configureClient('auth');
|
||||
final client = await auth.configureClient('auth');
|
||||
|
||||
final resp = await client.request(
|
||||
'/realms/${widget.realm.alias}/members',
|
||||
|
||||
@@ -63,7 +63,7 @@ class _StickerUploadDialogState extends State<StickerUploadDialog> {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
Response resp;
|
||||
final client = auth.configureClient('files');
|
||||
final client = await auth.configureClient('files');
|
||||
if (widget.edit == null) {
|
||||
resp = await client.post('/stickers', {
|
||||
'name': _nameController.text,
|
||||
|
||||
@@ -13,6 +13,7 @@ import firebase_analytics
|
||||
import firebase_core
|
||||
import firebase_crashlytics
|
||||
import firebase_messaging
|
||||
import flutter_local_notifications
|
||||
import flutter_secure_storage_macos
|
||||
import flutter_webrtc
|
||||
import gal
|
||||
@@ -41,6 +42,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||
FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin"))
|
||||
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
|
||||
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))
|
||||
|
||||
@@ -21,19 +21,19 @@ PODS:
|
||||
- Firebase/Messaging (11.0.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 11.0.0)
|
||||
- firebase_analytics (11.3.0):
|
||||
- firebase_analytics (11.3.1):
|
||||
- Firebase/Analytics (= 11.0.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_core (3.4.0):
|
||||
- firebase_core (3.4.1):
|
||||
- Firebase/CoreOnly (~> 11.0.0)
|
||||
- FlutterMacOS
|
||||
- firebase_crashlytics (4.1.0):
|
||||
- firebase_crashlytics (4.1.1):
|
||||
- Firebase/CoreOnly (~> 11.0.0)
|
||||
- Firebase/Crashlytics (~> 11.0.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_messaging (15.1.0):
|
||||
- firebase_messaging (15.1.1):
|
||||
- Firebase/CoreOnly (~> 11.0.0)
|
||||
- Firebase/Messaging (~> 11.0.0)
|
||||
- firebase_core
|
||||
@@ -97,6 +97,8 @@ PODS:
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesSwift (~> 2.1)
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- FlutterMacOS
|
||||
- flutter_secure_storage_macos (6.1.1):
|
||||
- FlutterMacOS
|
||||
- flutter_webrtc (0.11.3):
|
||||
@@ -156,7 +158,7 @@ PODS:
|
||||
- GoogleUtilities/UserDefaults (8.0.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- livekit_client (2.2.4):
|
||||
- livekit_client (2.2.5):
|
||||
- FlutterMacOS
|
||||
- WebRTC-SDK (= 125.6422.04)
|
||||
- macos_window_utils (1.0.0):
|
||||
@@ -194,6 +196,24 @@ PODS:
|
||||
- sqflite (0.0.3):
|
||||
- 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):
|
||||
- FlutterMacOS
|
||||
- "sqlite3 (~> 3.46.0+1)"
|
||||
- sqlite3/dbstatvtab
|
||||
- sqlite3/fts5
|
||||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
- url_launcher_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- wakelock_plus (0.0.1):
|
||||
@@ -209,6 +229,7 @@ DEPENDENCIES:
|
||||
- firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
|
||||
- firebase_crashlytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_crashlytics/macos`)
|
||||
- firebase_messaging (from `Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos`)
|
||||
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
|
||||
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
|
||||
- flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
@@ -226,6 +247,7 @@ DEPENDENCIES:
|
||||
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`)
|
||||
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
|
||||
|
||||
@@ -247,6 +269,7 @@ SPEC REPOS:
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- PromisesSwift
|
||||
- sqlite3
|
||||
- WebRTC-SDK
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
@@ -266,6 +289,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/firebase_crashlytics/macos
|
||||
firebase_messaging:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos
|
||||
flutter_local_notifications:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos
|
||||
flutter_secure_storage_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
|
||||
flutter_webrtc:
|
||||
@@ -300,6 +325,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||
sqflite:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin
|
||||
sqlite3_flutter_libs:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos
|
||||
url_launcher_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||
wakelock_plus:
|
||||
@@ -311,10 +338,10 @@ SPEC CHECKSUMS:
|
||||
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
|
||||
file_selector_macos: 54fdab7caa3ac3fc43c9fac4d7d8d231277f8cf2
|
||||
Firebase: 9f574c08c2396885b5e7e100ed4293d956218af9
|
||||
firebase_analytics: e9ae2af44afdaecf076797dcf9f3cd9c71ad8ac6
|
||||
firebase_core: ca9bcfb9835e1bcd5ff205e24a541f6bc04e7a35
|
||||
firebase_crashlytics: 87ec8afd46aeceddb565f7469df437c83fb0e01f
|
||||
firebase_messaging: c834894f659ce965ba4f93fe5d0dc5d705a3cc88
|
||||
firebase_analytics: 2169e28bb3ee1f765efe0fd4f5b5f625d92fda13
|
||||
firebase_core: 3f80bec72646b26618f0497e74ce8bcd608f03ca
|
||||
firebase_crashlytics: 6b1e511297406a6efd4405dc6301da8843b9dfe1
|
||||
firebase_messaging: ce70e6615f0cd906d80b7a651b960d76dad6de56
|
||||
FirebaseAnalytics: 27eb78b97880ea4a004839b9bac0b58880f5a92a
|
||||
FirebaseCore: 3cf438f431f18c12cdf2aaf64434648b63f7e383
|
||||
FirebaseCoreExtension: aa5c9779c2d0d39d83f1ceb3fdbafe80c4feecfa
|
||||
@@ -324,6 +351,7 @@ SPEC CHECKSUMS:
|
||||
FirebaseMessaging: d2d1d9c62c46dd2db49a952f7deb5b16ad2c9742
|
||||
FirebaseRemoteConfigInterop: abf8b1bbc0bf1b84abd22b66746926410bf91a87
|
||||
FirebaseSessions: 78f137e68dc01ca71606169ba4ac73b98c13752a
|
||||
flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4
|
||||
flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9
|
||||
flutter_webrtc: 2b4e4a2de70a1485836e40fd71a7a94c77d49bd9
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
@@ -331,7 +359,7 @@ SPEC CHECKSUMS:
|
||||
GoogleAppMeasurement: 6e49ffac7d3f2c3ded9cc663f912a13b67bbd0de
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
||||
livekit_client: 95f3b71e6545845aa658a6df0a3a62dcc3471d7c
|
||||
livekit_client: be04a950a4b84b9dbc87507ffad5154fe75fa067
|
||||
macos_window_utils: 933f91f64805e2eb91a5bd057cf97cd097276663
|
||||
media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82
|
||||
media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5
|
||||
@@ -347,6 +375,8 @@ SPEC CHECKSUMS:
|
||||
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb
|
||||
sqlite3_flutter_libs: 5ca46c1a04eddfbeeb5b16566164aa7ad1616e7b
|
||||
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
|
||||
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
|
||||
WebRTC-SDK: c3d69a87e7185fad3568f6f3cff7c9ac5890acf3
|
||||
|
||||
70
pubspec.lock
@@ -635,6 +635,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.0"
|
||||
flutter_background_service:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_background_service
|
||||
sha256: d32f078ec57647c9cfd6e1a8da9297f7d8f021d4dcc204a35aaad2cdbfe255f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.10"
|
||||
flutter_background_service_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_background_service_android
|
||||
sha256: "39da42dddf877beeef82bc2583130d8bedb4d0765e99ca9e7b4a32e8c6abd239"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.7"
|
||||
flutter_background_service_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_background_service_ios
|
||||
sha256: "6037ffd45c4d019dab0975c7feb1d31012dd697e25edc05505a4a9b0c7dc9fba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.3"
|
||||
flutter_background_service_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_background_service_platform_interface
|
||||
sha256: ca74aa95789a8304f4d3f57f07ba404faa86bed6e415f83e8edea6ad8b904a41
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.2"
|
||||
flutter_cache_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -715,6 +747,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
flutter_local_notifications:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: c500d5d9e7e553f06b61877ca6b9c8b92c570a4c8db371038702e8ce57f8a50f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "17.2.2"
|
||||
flutter_local_notifications_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_linux
|
||||
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
flutter_local_notifications_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_platform_interface
|
||||
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.0"
|
||||
flutter_markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1366,7 +1422,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
@@ -1902,10 +1958,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: synchronized
|
||||
sha256: a824e842b8a054f91a728b783c177c1e4731f6b124f9192468457a8913371255
|
||||
sha256: "51b08572b9f091f8c3eb4d9d4be253f196ff0075d5ec9b10a884026d5b55d7bc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
version: "3.3.0+2"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1930,6 +1986,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.0"
|
||||
timezone:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timezone
|
||||
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.4"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -2,7 +2,7 @@ name: solian
|
||||
description: "The Solar Network App"
|
||||
publish_to: "none"
|
||||
|
||||
version: 1.2.1+36
|
||||
version: 1.2.1+38
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.4 <4.0.0"
|
||||
@@ -78,6 +78,9 @@ dependencies:
|
||||
drift: ^2.20.2
|
||||
drift_flutter: ^0.2.0
|
||||
very_good_infinite_list: ^0.8.0
|
||||
path_provider: ^2.1.4
|
||||
flutter_background_service: ^5.0.10
|
||||
flutter_local_notifications: ^17.2.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@@ -124,9 +127,7 @@ flutter:
|
||||
weight: 700
|
||||
|
||||
flutter_launcher_icons:
|
||||
android:
|
||||
generate: "launcher_icon"
|
||||
image_path: "assets/icon.png"
|
||||
android: false
|
||||
ios: true
|
||||
image_path: "assets/icon.png"
|
||||
min_sdk_android: 21
|
||||
|
||||
5
web/drift_worker.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
import 'package:drift/wasm.dart';
|
||||
|
||||
// When compiled with dart2js, this file defines a dedicated or shared web
|
||||
// worker used by drift.
|
||||
void main() => WasmDatabase.workerMainForOpen();
|
||||
13325
web/drift_worker.dart.js
Normal file
662
web/drift_worker.dart.js.deps
Normal file
@@ -0,0 +1,662 @@
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/async.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/async_cache.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/async_memoizer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/byte_collector.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/cancelable_operation.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/chunked_stream_reader.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/delegate/event_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/delegate/future.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/delegate/sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/delegate/stream.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/delegate/stream_consumer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/delegate/stream_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/delegate/stream_subscription.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/future_group.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/lazy_stream.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/null_stream_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/restartable_timer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/capture_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/capture_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/error.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/future.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/release_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/release_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/result.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/result/value.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/single_subscription_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/sink_base.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_closer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_completer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_extensions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_group.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_queue.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_sink_completer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_sink_extensions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_sink_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_sink_transformer/handler_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_sink_transformer/reject_errors.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_sink_transformer/stream_transformer_wrapper.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_sink_transformer/typed.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_splitter.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_subscription_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/stream_zip.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/subscription_stream.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/typed/stream_subscription.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/async-2.11.0/lib/src/typed_stream_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/collection.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/algorithms.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/boollist.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/canonicalized_map.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/combined_wrappers/combined_iterable.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/combined_wrappers/combined_iterator.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/combined_wrappers/combined_list.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/combined_wrappers/combined_map.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/comparators.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/empty_unmodifiable_set.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/equality.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/equality_map.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/equality_set.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/functions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/iterable_extensions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/iterable_zip.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/list_extensions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/priority_queue.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/queue_list.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/union_set.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/union_set_controller.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/unmodifiable_wrappers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/utils.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/collection-1.18.0/lib/src/wrappers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/convert.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/accumulator_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/byte_accumulator_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/charcodes.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/codepage.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/fixed_datetime_formatter.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/hex.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/hex/decoder.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/hex/encoder.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/identity_codec.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/percent.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/percent/decoder.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/percent/encoder.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/string_accumulator_sink.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/src/utils.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/backends.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/drift.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/internal/versioned_schema.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/remote.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/dsl/columns.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/dsl/database.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/dsl/dsl.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/dsl/table.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/remote/client_impl.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/remote/communication.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/remote/protocol.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/remote/server_impl.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/remote/web_protocol.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/batch.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/connection.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/connection_user.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/dao_base.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/db_base.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/options.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/runtime_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/api/stream_updates.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/cancellation_zone.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/custom_result_set.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/data_class.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/data_verification.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/devtools/devtools.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/devtools/service_extension.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/devtools/shared.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/exceptions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/connection_pool.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/delayed_stream_queries.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/executor.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/helpers/delegates.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/helpers/engines.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/helpers/results.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/interceptor.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/stream_queries.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/executor/transactions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/manager/composable.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/manager/composer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/manager/filter.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/manager/manager.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/manager/ordering.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/manager/references.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/components/group_by.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/components/join.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/components/limit.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/components/order_by.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/components/subquery.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/components/table_valued_function.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/components/where.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/aggregate.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/algebra.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/bitwise.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/bools.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/case_when.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/comparable.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/custom.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/datetimes.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/exists.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/expression.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/in.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/internal.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/null_check.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/text.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/expressions/variables.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/generation_context.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/helpers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/migration.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/on_table.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/query_builder.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/schema/column_impl.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/schema/entities.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/schema/table_info.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/schema/view_info.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/statements/delete.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/statements/insert.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/statements/query.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/statements/select/custom_select.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/statements/select/select.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/statements/select/select_with_join.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/query_builder/statements/update.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/types/converters.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/types/mapping.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/runtime/utils.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/sqlite3/database.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/sqlite3/native_functions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/utils/async.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/utils/async_map.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/utils/lazy_database.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/utils/single_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/utils/synchronized.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/broadcast_stream_queries.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/channel_new.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/wasm_setup.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/wasm_setup/dedicated_worker.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/wasm_setup/protocol.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/wasm_setup/shared.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/wasm_setup/shared_worker.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/src/web/wasm_setup/types.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/drift-2.20.2/lib/wasm.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/meta-1.15.0/lib/meta.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/meta-1.15.0/lib/meta_meta.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/path.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/characters.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/context.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/internal_style.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/parsed_path.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/path_exception.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/path_map.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/path_set.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/style.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/style/posix.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/style/url.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/style/windows.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/path-1.9.0/lib/src/utils.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/common.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/constants.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/database.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/exception.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/functions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/implementation/bindings.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/implementation/database.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/implementation/exception.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/implementation/finalizer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/implementation/sqlite3.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/implementation/statement.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/implementation/utils.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/result_set.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/sqlite3.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/statement.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/vfs.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/bindings.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop/atomics.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop/core.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop/fetch.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop/indexed_db.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop/new_file_system_access.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop/typed_data.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/js_interop/wasm.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/sqlite3.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/vfs/async_opfs/client.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/vfs/async_opfs/sync_channel.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/vfs/async_opfs/worker.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/vfs/indexed_db.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/vfs/memory.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/vfs/simple_opfs.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/vfs/utils.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/src/wasm/wasm_interop.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/sqlite3-2.4.6/lib/wasm.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/chain.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/frame.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/lazy_chain.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/lazy_trace.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/stack_zone_specification.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/trace.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/unparsed_frame.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/utils.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/src/vm_trace.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stack_trace-1.11.1/lib/stack_trace.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/close_guarantee_channel.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/delegating_stream_channel.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/disconnector.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/guarantee_channel.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/json_document_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/multi_channel.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/stream_channel_completer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/stream_channel_controller.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/src/stream_channel_transformer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/stream_channel-2.1.2/lib/stream_channel.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/typed_data-1.3.2/lib/src/typed_buffer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/typed_data-1.3.2/lib/src/typed_queue.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/typed_data-1.3.2/lib/typed_buffers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/typed_data-1.3.2/lib/typed_data.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/accelerometer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/angle_instanced_arrays.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/attribution_reporting_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/background_sync.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/battery_status.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/clipboard_apis.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/compression.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/console.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/cookie_store.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/credential_management.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/csp.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_animations.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_animations_2.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_cascade.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_cascade_6.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_conditional.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_conditional_5.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_contain.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_counter_styles.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_font_loading.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_fonts.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_highlight_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_masking.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_paint_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_properties_values_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_transitions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_transitions_2.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_typed_om.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_view_transitions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/css_view_transitions_2.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/cssom.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/cssom_view.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/digital_identities.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/dom.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/dom_parsing.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/encoding.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/encrypted_media.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/entries_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/event_timing.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_blend_minmax.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_color_buffer_float.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_color_buffer_half_float.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_disjoint_timer_query.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_disjoint_timer_query_webgl2.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_float_blend.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_frag_depth.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_shader_texture_lod.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_srgb.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_texture_compression_bptc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_texture_compression_rgtc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_texture_filter_anisotropic.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ext_texture_norm16.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/fedcm.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/fetch.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/fido.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/fileapi.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/filter_effects.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/fs.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/fullscreen.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/gamepad.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/generic_sensor.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/geolocation.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/geometry.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/gyroscope.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/hr_time.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/html.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/image_capture.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/indexeddb.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/intersection_observer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/khr_parallel_shader_compile.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/largest_contentful_paint.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/mathml_core.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/media_capabilities.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/media_playback_quality.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/media_source.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/mediacapture_fromelement.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/mediacapture_streams.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/mediacapture_transform.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/mediasession.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/mediastream_recording.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/mst_content_hint.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/navigation_timing.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/netinfo.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/notifications.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_draw_buffers_indexed.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_element_index_uint.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_fbo_render_mipmap.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_standard_derivatives.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_texture_float.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_texture_float_linear.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_texture_half_float.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_texture_half_float_linear.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/oes_vertex_array_object.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/orientation_event.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/orientation_sensor.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/ovr_multiview2.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/paint_timing.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/payment_request.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/performance_timeline.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/permissions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/picture_in_picture.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/pointerevents.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/pointerlock.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/private_network_access.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/push_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/referrer_policy.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/remote_playback.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/reporting.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/requestidlecallback.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/resize_observer.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/resource_timing.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/saa_non_cookie_storage.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/sanitizer_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/scheduling_apis.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/screen_capture.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/screen_orientation.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/screen_wake_lock.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/secure_payment_confirmation.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/selection_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/server_timing.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/service_workers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/speech_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/storage.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/streams.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/svg.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/svg_animations.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/touch_events.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/trust_token_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/trusted_types.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/uievents.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/url.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/user_timing.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/vibration.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/video_rvfc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/wasm_js_api.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/web_animations.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/web_animations_2.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/web_bluetooth.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/web_locks.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/web_otp.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/web_share.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webaudio.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webauthn.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webcodecs.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webcodecs_av1_codec_registration.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webcodecs_avc_codec_registration.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webcodecs_hevc_codec_registration.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webcodecs_vp9_codec_registration.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webcryptoapi.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl1.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl2.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_color_buffer_float.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_compressed_texture_astc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_compressed_texture_etc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_compressed_texture_etc1.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_compressed_texture_pvrtc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_compressed_texture_s3tc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_compressed_texture_s3tc_srgb.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_debug_renderer_info.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_debug_shaders.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_depth_texture.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_draw_buffers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_lose_context.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgl_multi_draw.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webgpu.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webidl.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webmidi.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webrtc.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webrtc_encoded_transform.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webrtc_identity.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webrtc_priority.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/websockets.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webtransport.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webvtt.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webxr.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/webxr_hand_input.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/dom/xhr.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/enums.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/events/events.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/events/providers.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/events/streams.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/extensions.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/http.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/lists.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/src/helpers/renames.dart
|
||||
file:///Users/littlesheep/.pub-cache/hosted/pub.dev/web-1.0.0/lib/web.dart
|
||||
file:///Users/littlesheep/Documents/Projects/Hydrogen/Solian/.dart_tool/package_config.json
|
||||
file:///Users/littlesheep/Documents/Projects/Hydrogen/Solian/web/drift_worker.dart
|
||||
file:///opt/homebrew/Caskroom/flutter/3.24.3/flutter/bin/cache/dart-sdk/lib/_internal/dart2js_platform.dill
|
||||
file:///opt/homebrew/Caskroom/flutter/3.24.3/flutter/bin/cache/dart-sdk/lib/libraries.json
|
||||
org-dartlang-sdk:///lib/_http/crypto.dart
|
||||
org-dartlang-sdk:///lib/_http/embedder_config.dart
|
||||
org-dartlang-sdk:///lib/_http/http.dart
|
||||
org-dartlang-sdk:///lib/_http/http_date.dart
|
||||
org-dartlang-sdk:///lib/_http/http_headers.dart
|
||||
org-dartlang-sdk:///lib/_http/http_impl.dart
|
||||
org-dartlang-sdk:///lib/_http/http_parser.dart
|
||||
org-dartlang-sdk:///lib/_http/http_session.dart
|
||||
org-dartlang-sdk:///lib/_http/http_testing.dart
|
||||
org-dartlang-sdk:///lib/_http/overrides.dart
|
||||
org-dartlang-sdk:///lib/_http/websocket.dart
|
||||
org-dartlang-sdk:///lib/_http/websocket_impl.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/annotations.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/bigint_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/collection_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/constant_map.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/convert_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/core_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/dart2js_only.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/dart2js_runtime_metrics.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/developer_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/foreign_helper.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/instantiation.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/interceptors.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/internal_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/io_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/isolate_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_allow_interop_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_array.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_helper.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_names.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_number.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_primitives.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_string.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/late_helper.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/linked_hash_map.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/math_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/native_helper.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/native_typed_data.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/records.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/regexp_helper.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/string_helper.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/synced/async_status_codes.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/synced/embedded_names.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/synced/invocation_mirror_constants.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/synced/load_library_priority.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_runtime/lib/typed_data_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/convert_utf_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/date_time_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/js_interop_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/js_types.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/js_util_patch.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/rti.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/synced/embedded_names.dart
|
||||
org-dartlang-sdk:///lib/_internal/js_shared/lib/synced/recipe_syntax.dart
|
||||
org-dartlang-sdk:///lib/async/async.dart
|
||||
org-dartlang-sdk:///lib/async/async_error.dart
|
||||
org-dartlang-sdk:///lib/async/broadcast_stream_controller.dart
|
||||
org-dartlang-sdk:///lib/async/deferred_load.dart
|
||||
org-dartlang-sdk:///lib/async/future.dart
|
||||
org-dartlang-sdk:///lib/async/future_extensions.dart
|
||||
org-dartlang-sdk:///lib/async/future_impl.dart
|
||||
org-dartlang-sdk:///lib/async/schedule_microtask.dart
|
||||
org-dartlang-sdk:///lib/async/stream.dart
|
||||
org-dartlang-sdk:///lib/async/stream_controller.dart
|
||||
org-dartlang-sdk:///lib/async/stream_impl.dart
|
||||
org-dartlang-sdk:///lib/async/stream_pipe.dart
|
||||
org-dartlang-sdk:///lib/async/stream_transformers.dart
|
||||
org-dartlang-sdk:///lib/async/timer.dart
|
||||
org-dartlang-sdk:///lib/async/zone.dart
|
||||
org-dartlang-sdk:///lib/collection/collection.dart
|
||||
org-dartlang-sdk:///lib/collection/collections.dart
|
||||
org-dartlang-sdk:///lib/collection/hash_map.dart
|
||||
org-dartlang-sdk:///lib/collection/hash_set.dart
|
||||
org-dartlang-sdk:///lib/collection/iterable.dart
|
||||
org-dartlang-sdk:///lib/collection/iterator.dart
|
||||
org-dartlang-sdk:///lib/collection/linked_hash_map.dart
|
||||
org-dartlang-sdk:///lib/collection/linked_hash_set.dart
|
||||
org-dartlang-sdk:///lib/collection/linked_list.dart
|
||||
org-dartlang-sdk:///lib/collection/list.dart
|
||||
org-dartlang-sdk:///lib/collection/maps.dart
|
||||
org-dartlang-sdk:///lib/collection/queue.dart
|
||||
org-dartlang-sdk:///lib/collection/set.dart
|
||||
org-dartlang-sdk:///lib/collection/splay_tree.dart
|
||||
org-dartlang-sdk:///lib/convert/ascii.dart
|
||||
org-dartlang-sdk:///lib/convert/base64.dart
|
||||
org-dartlang-sdk:///lib/convert/byte_conversion.dart
|
||||
org-dartlang-sdk:///lib/convert/chunked_conversion.dart
|
||||
org-dartlang-sdk:///lib/convert/codec.dart
|
||||
org-dartlang-sdk:///lib/convert/convert.dart
|
||||
org-dartlang-sdk:///lib/convert/converter.dart
|
||||
org-dartlang-sdk:///lib/convert/encoding.dart
|
||||
org-dartlang-sdk:///lib/convert/html_escape.dart
|
||||
org-dartlang-sdk:///lib/convert/json.dart
|
||||
org-dartlang-sdk:///lib/convert/latin1.dart
|
||||
org-dartlang-sdk:///lib/convert/line_splitter.dart
|
||||
org-dartlang-sdk:///lib/convert/string_conversion.dart
|
||||
org-dartlang-sdk:///lib/convert/utf.dart
|
||||
org-dartlang-sdk:///lib/core/annotations.dart
|
||||
org-dartlang-sdk:///lib/core/bigint.dart
|
||||
org-dartlang-sdk:///lib/core/bool.dart
|
||||
org-dartlang-sdk:///lib/core/comparable.dart
|
||||
org-dartlang-sdk:///lib/core/core.dart
|
||||
org-dartlang-sdk:///lib/core/date_time.dart
|
||||
org-dartlang-sdk:///lib/core/double.dart
|
||||
org-dartlang-sdk:///lib/core/duration.dart
|
||||
org-dartlang-sdk:///lib/core/enum.dart
|
||||
org-dartlang-sdk:///lib/core/errors.dart
|
||||
org-dartlang-sdk:///lib/core/exceptions.dart
|
||||
org-dartlang-sdk:///lib/core/function.dart
|
||||
org-dartlang-sdk:///lib/core/identical.dart
|
||||
org-dartlang-sdk:///lib/core/int.dart
|
||||
org-dartlang-sdk:///lib/core/invocation.dart
|
||||
org-dartlang-sdk:///lib/core/iterable.dart
|
||||
org-dartlang-sdk:///lib/core/iterator.dart
|
||||
org-dartlang-sdk:///lib/core/list.dart
|
||||
org-dartlang-sdk:///lib/core/map.dart
|
||||
org-dartlang-sdk:///lib/core/null.dart
|
||||
org-dartlang-sdk:///lib/core/num.dart
|
||||
org-dartlang-sdk:///lib/core/object.dart
|
||||
org-dartlang-sdk:///lib/core/pattern.dart
|
||||
org-dartlang-sdk:///lib/core/print.dart
|
||||
org-dartlang-sdk:///lib/core/record.dart
|
||||
org-dartlang-sdk:///lib/core/regexp.dart
|
||||
org-dartlang-sdk:///lib/core/set.dart
|
||||
org-dartlang-sdk:///lib/core/sink.dart
|
||||
org-dartlang-sdk:///lib/core/stacktrace.dart
|
||||
org-dartlang-sdk:///lib/core/stopwatch.dart
|
||||
org-dartlang-sdk:///lib/core/string.dart
|
||||
org-dartlang-sdk:///lib/core/string_buffer.dart
|
||||
org-dartlang-sdk:///lib/core/string_sink.dart
|
||||
org-dartlang-sdk:///lib/core/symbol.dart
|
||||
org-dartlang-sdk:///lib/core/type.dart
|
||||
org-dartlang-sdk:///lib/core/uri.dart
|
||||
org-dartlang-sdk:///lib/core/weak.dart
|
||||
org-dartlang-sdk:///lib/developer/developer.dart
|
||||
org-dartlang-sdk:///lib/developer/extension.dart
|
||||
org-dartlang-sdk:///lib/developer/http_profiling.dart
|
||||
org-dartlang-sdk:///lib/developer/profiler.dart
|
||||
org-dartlang-sdk:///lib/developer/service.dart
|
||||
org-dartlang-sdk:///lib/developer/timeline.dart
|
||||
org-dartlang-sdk:///lib/html/dart2js/html_dart2js.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/conversions.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/conversions_dart2js.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/css_class_set.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/device.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/filtered_element_list.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/html_common_dart2js.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/lists.dart
|
||||
org-dartlang-sdk:///lib/html/html_common/metadata.dart
|
||||
org-dartlang-sdk:///lib/indexed_db/dart2js/indexed_db_dart2js.dart
|
||||
org-dartlang-sdk:///lib/internal/async_cast.dart
|
||||
org-dartlang-sdk:///lib/internal/bytes_builder.dart
|
||||
org-dartlang-sdk:///lib/internal/cast.dart
|
||||
org-dartlang-sdk:///lib/internal/errors.dart
|
||||
org-dartlang-sdk:///lib/internal/internal.dart
|
||||
org-dartlang-sdk:///lib/internal/iterable.dart
|
||||
org-dartlang-sdk:///lib/internal/linked_list.dart
|
||||
org-dartlang-sdk:///lib/internal/list.dart
|
||||
org-dartlang-sdk:///lib/internal/patch.dart
|
||||
org-dartlang-sdk:///lib/internal/print.dart
|
||||
org-dartlang-sdk:///lib/internal/sort.dart
|
||||
org-dartlang-sdk:///lib/internal/symbol.dart
|
||||
org-dartlang-sdk:///lib/io/common.dart
|
||||
org-dartlang-sdk:///lib/io/data_transformer.dart
|
||||
org-dartlang-sdk:///lib/io/directory.dart
|
||||
org-dartlang-sdk:///lib/io/directory_impl.dart
|
||||
org-dartlang-sdk:///lib/io/embedder_config.dart
|
||||
org-dartlang-sdk:///lib/io/eventhandler.dart
|
||||
org-dartlang-sdk:///lib/io/file.dart
|
||||
org-dartlang-sdk:///lib/io/file_impl.dart
|
||||
org-dartlang-sdk:///lib/io/file_system_entity.dart
|
||||
org-dartlang-sdk:///lib/io/io.dart
|
||||
org-dartlang-sdk:///lib/io/io_resource_info.dart
|
||||
org-dartlang-sdk:///lib/io/io_service.dart
|
||||
org-dartlang-sdk:///lib/io/io_sink.dart
|
||||
org-dartlang-sdk:///lib/io/link.dart
|
||||
org-dartlang-sdk:///lib/io/namespace_impl.dart
|
||||
org-dartlang-sdk:///lib/io/network_profiling.dart
|
||||
org-dartlang-sdk:///lib/io/overrides.dart
|
||||
org-dartlang-sdk:///lib/io/platform.dart
|
||||
org-dartlang-sdk:///lib/io/platform_impl.dart
|
||||
org-dartlang-sdk:///lib/io/process.dart
|
||||
org-dartlang-sdk:///lib/io/secure_server_socket.dart
|
||||
org-dartlang-sdk:///lib/io/secure_socket.dart
|
||||
org-dartlang-sdk:///lib/io/security_context.dart
|
||||
org-dartlang-sdk:///lib/io/service_object.dart
|
||||
org-dartlang-sdk:///lib/io/socket.dart
|
||||
org-dartlang-sdk:///lib/io/stdio.dart
|
||||
org-dartlang-sdk:///lib/io/string_transformer.dart
|
||||
org-dartlang-sdk:///lib/io/sync_socket.dart
|
||||
org-dartlang-sdk:///lib/isolate/capability.dart
|
||||
org-dartlang-sdk:///lib/isolate/isolate.dart
|
||||
org-dartlang-sdk:///lib/js/_js.dart
|
||||
org-dartlang-sdk:///lib/js/_js_annotations.dart
|
||||
org-dartlang-sdk:///lib/js/_js_client.dart
|
||||
org-dartlang-sdk:///lib/js/js.dart
|
||||
org-dartlang-sdk:///lib/js_interop/js_interop.dart
|
||||
org-dartlang-sdk:///lib/js_interop_unsafe/js_interop_unsafe.dart
|
||||
org-dartlang-sdk:///lib/js_util/js_util.dart
|
||||
org-dartlang-sdk:///lib/math/math.dart
|
||||
org-dartlang-sdk:///lib/math/point.dart
|
||||
org-dartlang-sdk:///lib/math/random.dart
|
||||
org-dartlang-sdk:///lib/math/rectangle.dart
|
||||
org-dartlang-sdk:///lib/svg/dart2js/svg_dart2js.dart
|
||||
org-dartlang-sdk:///lib/typed_data/typed_data.dart
|
||||
org-dartlang-sdk:///lib/web_audio/dart2js/web_audio_dart2js.dart
|
||||
org-dartlang-sdk:///lib/web_gl/dart2js/web_gl_dart2js.dart
|
||||
16
web/drift_worker.dart.js.map
Normal file
@@ -35,6 +35,8 @@
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
|
||||
|
||||
|
||||
<style id="splash-screen-style">
|
||||
html {
|
||||
height: 100%
|
||||
@@ -106,6 +108,7 @@
|
||||
document.body.style.background = "transparent";
|
||||
}
|
||||
</script>
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -115,6 +118,7 @@
|
||||
<img class="center" aria-hidden="true" src="splash/img/light-1x.png" alt="">
|
||||
</picture>
|
||||
|
||||
|
||||
<script src="flutter_bootstrap.js" async=""></script>
|
||||
|
||||
|
||||
|
||||