Compare commits
6 Commits
40b885b27b
...
1.2.1+37
| Author | SHA1 | Date | |
|---|---|---|---|
| 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>
|
||||
@@ -54,6 +54,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",
|
||||
@@ -373,7 +375,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 +395,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"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"settings": "设置",
|
||||
"settingsNotificationBgService": "常驻通知服务",
|
||||
"settingsNotificationBgServiceDesc": "在设备常驻一个通知服务,使得部分不支持推送通知的设备可以在后台收到通知;启用该功能的情况下不会向服务器注册推送通知,并且你会始终在他人眼中成为在线(隐身除外);可能需要在设置中关闭电量与流量优化。",
|
||||
"page": "页面",
|
||||
"draft": "草稿",
|
||||
"draftSave": "存为草稿",
|
||||
@@ -374,7 +376,8 @@
|
||||
"callStatusReconnected": "重连中",
|
||||
"messageOutOfSync": "消息可能与服务器脱节",
|
||||
"messageOutOfSyncCaption": "由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。",
|
||||
"messageHistoryWipe": "清除消息记录",
|
||||
"localDatabaseWipe": "清除本地数据库",
|
||||
"localDatabaseSize": "本地数据库大小:@size",
|
||||
"unknown": "未知",
|
||||
"collapse": "折叠",
|
||||
"expand": "展开",
|
||||
@@ -393,5 +396,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',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ 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/providers/database/database.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/services.dart';
|
||||
|
||||
@@ -198,6 +200,9 @@ class AuthProvider extends GetConnect {
|
||||
Get.find<WebSocketProvider>().notifications.clear();
|
||||
Get.find<WebSocketProvider>().notificationUnread.value = 0;
|
||||
|
||||
AppDatabase.removeDatabase();
|
||||
autoStopBackgroundNotificationService();
|
||||
|
||||
storage.deleteAll();
|
||||
}
|
||||
|
||||
@@ -211,6 +216,7 @@ class AuthProvider extends GetConnect {
|
||||
}
|
||||
|
||||
Future<void> refreshUserProfile() async {
|
||||
if (!isAuthorized.value) return;
|
||||
final client = configureClient('auth');
|
||||
final resp = await client.get('/users/me');
|
||||
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';
|
||||
@@ -17,8 +22,24 @@ class AppDatabase extends _$AppDatabase {
|
||||
static QueryExecutor _openConnection() {
|
||||
return driftDatabase(name: 'solar_network_local_db');
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -120,6 +152,12 @@ class WebSocketProvider extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> registerPushNotifications() async {
|
||||
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;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ 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/exts.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
@@ -22,7 +23,7 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
final _usernameController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
|
||||
void requestResetPassword() async {
|
||||
void _requestResetPassword() async {
|
||||
final username = _usernameController.value.text;
|
||||
if (username.isEmpty) {
|
||||
context.showErrorDialog('signinResetPasswordHint'.tr);
|
||||
@@ -52,7 +53,7 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
context.showModalDialog('done'.tr, 'signinResetPasswordSent'.tr);
|
||||
}
|
||||
|
||||
void performAction() async {
|
||||
void _performAction() async {
|
||||
final AuthProvider auth = Get.find();
|
||||
|
||||
final username = _usernameController.value.text;
|
||||
@@ -100,6 +101,8 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
}
|
||||
|
||||
Get.find<WebSocketProvider>().registerPushNotifications();
|
||||
autoConfigureBackgroundNotificationService();
|
||||
autoStartBackgroundNotificationService();
|
||||
|
||||
Navigator.pop(context, true);
|
||||
}
|
||||
@@ -121,7 +124,7 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
final uri = url.replaceFirst('solink://', '');
|
||||
if (uri == 'auth?status=done') {
|
||||
closeInAppWebView();
|
||||
performAction();
|
||||
_performAction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,19 +178,19 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onSubmitted: (_) => performAction(),
|
||||
onSubmitted: (_) => _performAction(),
|
||||
),
|
||||
const Gap(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: _isBusy ? null : () => requestResetPassword(),
|
||||
onPressed: _isBusy ? null : () => _requestResetPassword(),
|
||||
style: TextButton.styleFrom(foregroundColor: Colors.grey),
|
||||
child: Text('forgotPassword'.tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _isBusy ? null : () => performAction(),
|
||||
onPressed: _isBusy ? null : () => _performAction(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
||||
@@ -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,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();
|
||||
|
||||
@@ -367,7 +347,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 +482,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,
|
||||
|
||||
@@ -204,7 +204,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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
66
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
|
||||
@@ -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+37
|
||||
|
||||
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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||