Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
153c15e5c9 | |||
6a0f42cdc9 | |||
01aaa5455e | |||
f3ceb5f967 | |||
b5e2fa4c25 | |||
8378024490 | |||
6d40d6bba3 | |||
77075c8dab | |||
dec34e297d | |||
358677ade0 | |||
d2f37ae45d |
@ -1,4 +1,4 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="dev.solsynth.solian">
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
||||
|
@ -18,7 +18,7 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version '8.4.0' apply false
|
||||
id "com.android.application" version '8.6.0' apply false
|
||||
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||
id "com.google.firebase.crashlytics" version "2.8.1" apply false
|
||||
id "org.jetbrains.kotlin.android" version '2.0.0' apply false
|
||||
|
@ -55,7 +55,7 @@
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"settings": "Settings",
|
||||
"settingsNotificationBgService": "Background Notification Service",
|
||||
"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",
|
||||
@ -68,6 +68,11 @@
|
||||
"notificationUnreadCount": "@count unread notifications",
|
||||
"errorHappened": "An error occurred",
|
||||
"errorHappenedUnauthorized": "Unauthorized request, please sign in or try resign in.",
|
||||
"errorHappenedRequestBad": "Request error, the server refused to process the request. Please check your request data.",
|
||||
"errorHappenedRequestForbidden": "Request error, insufficient permissions.",
|
||||
"errorHappenedRequestNotFound": "Request error, the requested data does not exist.",
|
||||
"errorHappenedRequestConnection": "Network request failed. Please check the connection status and service status, then try again.",
|
||||
"errorHappenedRequestUnknown": "Request error, unknown type. Please take a full screenshot of this message and submit feedback.",
|
||||
"forgotPassword": "Forgot password",
|
||||
"email": "Email",
|
||||
"username": "Username",
|
||||
@ -350,8 +355,7 @@
|
||||
"bsCheckForUpdate": "Checking For Updates",
|
||||
"bsCheckForUpdateFailed": "Unable to Check Updates",
|
||||
"bsCheckForUpdateNew": "Found New Version",
|
||||
"bsCheckForUpdateDescApple": "Please head to TestFlight and update your app to latest version to prevent error happens and get latest functions.",
|
||||
"bsCheckForUpdateDescCommon": "Please head to our website download and install latest version of application to prevent error happens and get latest functions.",
|
||||
"bsCheckForUpdateDesc": "Please head to app store and update your app to latest version to prevent error happens and get latest functions.",
|
||||
"bsCheckingServer": "Checking Server Status",
|
||||
"bsCheckingServerFail": "Unable connect to server, check your network connection",
|
||||
"bsCheckingServerDown": "Server currently unavailable, please retry later",
|
||||
@ -422,5 +426,11 @@
|
||||
"notificationTopicPostFeedback": "Post feedbacks",
|
||||
"notificationTopicPostSubscription": "Post subscriptions",
|
||||
"preferencesApplied": "Preferences has been applied.",
|
||||
"save": "Save"
|
||||
"save": "Save",
|
||||
"updateAvailable": "Update available",
|
||||
"updateAvailableDesc": "There is an update available (@version). Do you want to download and install it now? You can still use the app normally while waiting for the download to complete.",
|
||||
"update": "Update",
|
||||
"updateCheckStrictly": "Strict mode",
|
||||
"updateCheckStrictlyDesc": "If enabled, the app will ask for updating once the local version is different from remote one.",
|
||||
"updateMayAvailable": "App version @version is available, you can update from app store or our website."
|
||||
}
|
||||
|
@ -351,8 +351,7 @@
|
||||
"bsCheckForUpdate": "正在检查更新",
|
||||
"bsCheckForUpdateFailed": "无法检查更新",
|
||||
"bsCheckForUpdateNew": "发现新版本",
|
||||
"bsCheckForUpdateDescApple": "请前往 TestFlight 并将您的应用程序更新到最新版本,以防止出现错误并获取最新功能。",
|
||||
"bsCheckForUpdateDescCommon": "请前往我们的网站下载并安装最新版本的应用程序,以防止出现错误并获取最新功能。",
|
||||
"bsCheckForUpdateDesc": "请前往应用商店并将您的应用程序更新到最新版本,以防止出现错误并获取最新功能。",
|
||||
"bsCheckingServer": "检查服务器状态中",
|
||||
"bsCheckingServerFail": "无法连接至服务器,请检查你的网络连接状态",
|
||||
"bsCheckingServerDown": "当前服务器不可用,请稍后重试",
|
||||
@ -423,5 +422,11 @@
|
||||
"notificationTopicPostFeedback": "帖子反馈",
|
||||
"notificationTopicPostSubscription": "订阅源",
|
||||
"preferencesApplied": "偏好设置已应用",
|
||||
"save": "保存"
|
||||
"save": "保存",
|
||||
"updateAvailable": "有可用更新",
|
||||
"updateAvailableDesc": "有可用更新 (@from 到 @to) 你想现在下载安装吗?在等待下载期间你仍可以正常使用。",
|
||||
"update": "更新",
|
||||
"updateCheckStrictly": "严格模式",
|
||||
"updateCheckStrictlyDesc": "如果启用,应用程序将会在本地版本与远程版本不同时询问更新,而不会检查版本号大小。",
|
||||
"updateMayAvailable": "版本 @version 现已可用,你可以前往应用商店或是我们的官网下载更新。"
|
||||
}
|
||||
|
@ -54,22 +54,22 @@ PODS:
|
||||
- Firebase/Performance (11.0.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebasePerformance (~> 11.0.0)
|
||||
- firebase_analytics (11.3.1):
|
||||
- firebase_analytics (11.3.2):
|
||||
- Firebase/Analytics (= 11.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_core (3.4.1):
|
||||
- firebase_core (3.5.0):
|
||||
- Firebase/CoreOnly (= 11.0.0)
|
||||
- Flutter
|
||||
- firebase_crashlytics (4.1.1):
|
||||
- firebase_crashlytics (4.1.2):
|
||||
- Firebase/Crashlytics (= 11.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_messaging (15.1.1):
|
||||
- firebase_messaging (15.1.2):
|
||||
- Firebase/Messaging (= 11.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_performance (0.10.0-6):
|
||||
- firebase_performance (0.10.0-7):
|
||||
- Firebase/Performance (= 11.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
@ -154,6 +154,8 @@ PODS:
|
||||
- PromisesSwift (~> 2.1)
|
||||
- FirebaseSharedSwift (11.2.0)
|
||||
- Flutter (1.0.0)
|
||||
- flutter_app_update (0.0.1):
|
||||
- Flutter
|
||||
- flutter_background_service_ios (0.0.3):
|
||||
- Flutter
|
||||
- flutter_keyboard_visibility (0.0.1):
|
||||
@ -306,6 +308,7 @@ DEPENDENCIES:
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- firebase_performance (from `.symlinks/plugins/firebase_performance/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
|
||||
- flutter_background_service_ios (from `.symlinks/plugins/flutter_background_service_ios/ios`)
|
||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
@ -383,6 +386,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/firebase_performance/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_app_update:
|
||||
:path: ".symlinks/plugins/flutter_app_update/ios"
|
||||
flutter_background_service_ios:
|
||||
:path: ".symlinks/plugins/flutter_background_service_ios/ios"
|
||||
flutter_keyboard_visibility:
|
||||
@ -445,11 +450,11 @@ SPEC CHECKSUMS:
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
Firebase: 9f574c08c2396885b5e7e100ed4293d956218af9
|
||||
firebase_analytics: b8ce6c2c4b245d3c3bb3a147965d09da0f455959
|
||||
firebase_core: ba84e940cf5cbbc601095f86556560937419195c
|
||||
firebase_crashlytics: 4111f8198b78c99471c955af488cecd8224967e6
|
||||
firebase_messaging: c40f84e7a98da956d5262fada373b5c458edcf13
|
||||
firebase_performance: 8b7b9ca5adf3a9b3afa12b4eb96b9cabefc2c248
|
||||
firebase_analytics: 4fd10182fd08bb8358f26ac8aca8dad7b6d0f592
|
||||
firebase_core: 2ec6b789859c7c24766344ec71fdf78639402d56
|
||||
firebase_crashlytics: 60630a0f91ee432275fa1660fd8593079761448a
|
||||
firebase_messaging: a18e1e02b2e8e69097c8173e0c851be223b21c50
|
||||
firebase_performance: 12d45fdf120992fa879d990929bf73d4a5ced053
|
||||
FirebaseABTesting: 2104d957ce33888a3d6f3bde298cdee376dde8f1
|
||||
FirebaseAnalytics: 27eb78b97880ea4a004839b9bac0b58880f5a92a
|
||||
FirebaseCore: 3cf438f431f18c12cdf2aaf64434648b63f7e383
|
||||
@ -464,6 +469,7 @@ SPEC CHECKSUMS:
|
||||
FirebaseSessions: adcec8b72d0066a385e3affcd1bcb1ebb3908ce6
|
||||
FirebaseSharedSwift: 7a0d78d155ede78407f0fdc89fbc914014c7c540
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_app_update: 65f61da626cb111d1b24674abc4b01728d7723bc
|
||||
flutter_background_service_ios: e30e0d3ee69e4cee66272d0c78eacd48c2e94aac
|
||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
|
@ -1,8 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:solian/exts.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
import 'package:solian/providers/auth.dart';
|
||||
@ -13,6 +16,8 @@ import 'package:solian/providers/theme_switcher.dart';
|
||||
import 'package:solian/providers/websocket.dart';
|
||||
import 'package:solian/services.dart';
|
||||
import 'package:solian/widgets/sized_container.dart';
|
||||
import 'package:flutter_app_update/flutter_app_update.dart';
|
||||
import 'package:version/version.dart';
|
||||
|
||||
class BootstrapperShell extends StatefulWidget {
|
||||
final Widget child;
|
||||
@ -34,6 +39,8 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
|
||||
int _periodCursor = 0;
|
||||
|
||||
final Completer _bootCompleter = Completer();
|
||||
|
||||
late final List<({String label, Future<void> Function() action})> _periods = [
|
||||
(
|
||||
label: 'bsLoadingTheme',
|
||||
@ -46,24 +53,60 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
action: () async {
|
||||
if (PlatformInfo.isWeb) return;
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
final localVersionString = '${info.version}+${info.buildNumber}';
|
||||
final resp = await GetConnect().get(
|
||||
'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?limit=1',
|
||||
'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?page=1&limit=1',
|
||||
);
|
||||
if (resp.body[0]['name'] != localVersionString) {
|
||||
final remoteVersionString =
|
||||
(resp.body as List).firstOrNull?['name'] ?? '0.0.0';
|
||||
final remoteVersion = Version.parse(remoteVersionString ?? '0.0.0');
|
||||
final localVersion =
|
||||
Version.parse(localVersionString.split('+').first);
|
||||
final strictUpdate = prefs.getBool('check_update_strictly') ?? false;
|
||||
if (remoteVersion > localVersion ||
|
||||
(remoteVersionString != localVersionString && strictUpdate)) {
|
||||
setState(() {
|
||||
_isErrored = true;
|
||||
_subtitle = PlatformInfo.isIOS || PlatformInfo.isMacOS
|
||||
? 'bsCheckForUpdateDescApple'.tr
|
||||
: 'bsCheckForUpdateDescCommon'.tr;
|
||||
_subtitle = 'bsCheckForUpdateDesc'.tr;
|
||||
});
|
||||
|
||||
if (PlatformInfo.isAndroid) {
|
||||
context
|
||||
.showConfirmDialog(
|
||||
'updateAvailable'.tr,
|
||||
'updateAvailableDesc'.trParams({
|
||||
'from': localVersionString,
|
||||
'to': remoteVersionString,
|
||||
}),
|
||||
)
|
||||
.then((result) {
|
||||
if (result) {
|
||||
final model = UpdateModel(
|
||||
'https://files.solsynth.dev/d/production01/solian/app-arm64-v8a-release.apk',
|
||||
'solian-app-arm64-v8a-release.apk',
|
||||
'ic_launcher',
|
||||
'https://testflight.apple.com/join/YJ0lmN6O',
|
||||
);
|
||||
AzhonAppUpdate.update(model);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_isErrored = true;
|
||||
_subtitle = 'bsCheckForUpdateDesc'.tr;
|
||||
});
|
||||
}
|
||||
} else if (remoteVersionString != localVersionString) {
|
||||
_bootCompleter.future.then((_) {
|
||||
context.showSnackbar('updateMayAvailable'.trParams({
|
||||
'version': remoteVersionString,
|
||||
}));
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_isErrored = true;
|
||||
_subtitle = 'bsCheckForUpdateFailed'.tr;
|
||||
});
|
||||
context.showErrorDialog('Unable to check update: $e');
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -154,6 +197,9 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
}
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
_bootCompleter.complete();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,6 +297,9 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
||||
_isBusy = false;
|
||||
_isErrored = false;
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
_bootCompleter.complete();
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_isBusy = true;
|
||||
|
@ -51,6 +51,28 @@ extension AppExtensions on BuildContext {
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> showConfirmDialog(String title, body) async {
|
||||
return await showDialog<bool>(
|
||||
useRootNavigator: true,
|
||||
context: this,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(title),
|
||||
content: Text(body),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, false),
|
||||
child: Text('cancel'.tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: Text('okay'.tr),
|
||||
)
|
||||
],
|
||||
),
|
||||
) ??
|
||||
false;
|
||||
}
|
||||
|
||||
Future<void> showErrorDialog(dynamic exception) {
|
||||
Widget content = Text(exception.toString().capitalize!);
|
||||
if (exception is UnauthorizedException) {
|
||||
|
@ -9,7 +9,6 @@ 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';
|
||||
import 'package:solian/providers/attachment_uploader.dart';
|
||||
@ -123,9 +122,7 @@ class SolianApp extends StatelessWidget {
|
||||
builder: (context, child) {
|
||||
return SystemShell(
|
||||
child: ScaffoldMessenger(
|
||||
child: BootstrapperShell(
|
||||
child: child ?? const SizedBox.shrink(),
|
||||
),
|
||||
child: child ?? const SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -89,13 +89,13 @@ class ChannelProvider extends GetxController {
|
||||
return resp;
|
||||
}
|
||||
|
||||
Future<Response> listAvailableChannel({String realm = 'global'}) async {
|
||||
Future<Response> listAvailableChannel({String scope = 'global'}) async {
|
||||
final AuthProvider auth = Get.find();
|
||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||
|
||||
final client = await auth.configureClient('messaging');
|
||||
|
||||
final resp = await client.get('/channels/$realm/me/available');
|
||||
final resp = await client.get('/channels/$scope/me/available');
|
||||
if (resp.statusCode != 200) {
|
||||
throw RequestException(resp);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:solian/bootstrapper.dart';
|
||||
import 'package:solian/models/realm.dart';
|
||||
import 'package:solian/screens/about.dart';
|
||||
import 'package:solian/screens/account.dart';
|
||||
@ -32,9 +33,12 @@ abstract class AppRouter {
|
||||
static GoRouter instance = GoRouter(
|
||||
routes: [
|
||||
ShellRoute(
|
||||
builder: (context, state, child) => RootShell(
|
||||
state: state,
|
||||
child: child,
|
||||
builder: (context, state, child) => BootstrapperShell(
|
||||
key: const Key('global-bootstrapper'),
|
||||
child: RootShell(
|
||||
state: state,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
routes: [
|
||||
GoRoute(
|
||||
|
@ -115,6 +115,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
||||
leading: const Icon(Icons.settings),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title: Text('channelSettings'.tr),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
onTap: () async {
|
||||
AppRouter.instance
|
||||
.pushNamed(
|
||||
@ -174,6 +175,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
||||
ListTile(
|
||||
leading: const Icon(Icons.notifications_active),
|
||||
title: Text('channelNotifyLevel'.tr),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
trailing: DropdownButtonHideUnderline(
|
||||
child: DropdownButton2<int>(
|
||||
isExpanded: true,
|
||||
@ -206,6 +208,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
leading: const Icon(Icons.supervisor_account),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
title: Text('channelMembers'.tr),
|
||||
@ -214,6 +217,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
||||
...(_isOwned ? ownerActions : List.empty()),
|
||||
const Divider(thickness: 0.3),
|
||||
ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
leading: _isOwned
|
||||
? const Icon(Icons.delete)
|
||||
: const Icon(Icons.exit_to_app),
|
||||
|
@ -183,18 +183,18 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
||||
children: [
|
||||
ListTile(
|
||||
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||
title: Row(
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_editorController.title ?? 'title'.tr,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const Gap(6),
|
||||
if (_editorController.aliasController.text.isNotEmpty)
|
||||
Badge(
|
||||
label: Text('#${_editorController.aliasController.text}'),
|
||||
),
|
||||
).paddingOnly(bottom: 2),
|
||||
],
|
||||
),
|
||||
subtitle: Text(
|
||||
|
@ -34,7 +34,7 @@ class _RealmViewScreenState extends State<RealmViewScreen> {
|
||||
final List<Channel> _channels = List.empty(growable: true);
|
||||
|
||||
getRealm({String? overrideAlias}) async {
|
||||
final RealmProvider provider = Get.find();
|
||||
final RealmProvider realm = Get.find();
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
@ -43,7 +43,7 @@ class _RealmViewScreenState extends State<RealmViewScreen> {
|
||||
}
|
||||
|
||||
try {
|
||||
final resp = await provider.getRealm(_overrideAlias ?? widget.alias);
|
||||
final resp = await realm.getRealm(_overrideAlias ?? widget.alias);
|
||||
setState(() => _realm = Realm.fromJson(resp.body));
|
||||
} catch (e) {
|
||||
context.showErrorDialog(e);
|
||||
@ -55,14 +55,26 @@ class _RealmViewScreenState extends State<RealmViewScreen> {
|
||||
getChannels() async {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final ChannelProvider provider = Get.find();
|
||||
final resp = await provider.listChannel(scope: _realm!.alias);
|
||||
final ChannelProvider channel = Get.find();
|
||||
final resp = await channel.listChannel(scope: _realm!.alias);
|
||||
final availableResp = await channel.listAvailableChannel(
|
||||
scope: _realm!.alias,
|
||||
);
|
||||
|
||||
final Set<int> channelIdx = {};
|
||||
|
||||
setState(() {
|
||||
_channels.clear();
|
||||
_channels.addAll(
|
||||
resp.body.map((e) => Channel.fromJson(e)).toList().cast<Channel>(),
|
||||
);
|
||||
_channels.addAll(
|
||||
availableResp.body
|
||||
.map((e) => Channel.fromJson(e))
|
||||
.toList()
|
||||
.cast<Channel>(),
|
||||
);
|
||||
_channels.retainWhere((x) => channelIdx.add(x.id));
|
||||
});
|
||||
|
||||
setState(() => _isBusy = false);
|
||||
|
@ -114,6 +114,21 @@ class _SettingScreenState extends State<SettingScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
_buildCaptionHeader('update'.tr),
|
||||
CheckboxListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 22),
|
||||
secondary: const Icon(Icons.sync_alt),
|
||||
title: Text('updateCheckStrictly'.tr),
|
||||
subtitle: Text('updateCheckStrictlyDesc'.tr),
|
||||
value: _prefs?.getBool('check_update_strictly') ?? false,
|
||||
onChanged: (value) {
|
||||
_prefs
|
||||
?.setBool('check_update_strictly', value ?? false)
|
||||
.then((_) {
|
||||
setState(() {});
|
||||
});
|
||||
},
|
||||
),
|
||||
_buildCaptionHeader('more'.tr),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.delete_sweep),
|
||||
|
@ -484,7 +484,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${fileType[0].toUpperCase()}${fileType.substring(1)} · ${element.size.formatBytes()}',
|
||||
'${fileType.isNotEmpty ? fileType.capitalize : 'unknown'.tr} · ${element.size.formatBytes()}',
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
],
|
||||
|
@ -233,6 +233,7 @@ class _AttachmentItemVideoState extends State<_AttachmentItemVideo> {
|
||||
final ratio = widget.item.metadata?['ratio'] ?? 16 / 9;
|
||||
if (!_showContent) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Stack(
|
||||
children: [
|
||||
if (widget.item.metadata?['thumbnail'] != null)
|
||||
@ -400,6 +401,7 @@ class _AttachmentItemAudioState extends State<_AttachmentItemAudio> {
|
||||
const ratio = 16 / 9;
|
||||
if (!_showContent) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Stack(
|
||||
children: [
|
||||
if (widget.item.metadata?['thumbnail'] != null)
|
||||
|
@ -10,6 +10,7 @@ class AutoCacheImage extends StatelessWidget {
|
||||
final BoxFit? fit;
|
||||
final bool noProgressIndicator;
|
||||
final bool noErrorWidget;
|
||||
final bool isDense;
|
||||
|
||||
const AutoCacheImage(
|
||||
this.url, {
|
||||
@ -19,6 +20,7 @@ class AutoCacheImage extends StatelessWidget {
|
||||
this.fit,
|
||||
this.noProgressIndicator = false,
|
||||
this.noErrorWidget = false,
|
||||
this.isDense = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -46,13 +48,14 @@ class AutoCacheImage extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.close, size: 32)
|
||||
Icon(Icons.close, size: isDense ? 24 : 32)
|
||||
.animate(onPlay: (e) => e.repeat(reverse: true))
|
||||
.fade(duration: 500.ms),
|
||||
Text(
|
||||
error.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (!isDense)
|
||||
Text(
|
||||
error.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -89,13 +92,14 @@ class AutoCacheImage extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.close, size: 32)
|
||||
Icon(Icons.close, size: isDense ? 24 : 32)
|
||||
.animate(onPlay: (e) => e.repeat(reverse: true))
|
||||
.fade(duration: 500.ms),
|
||||
Text(
|
||||
error.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (!isDense)
|
||||
Text(
|
||||
error.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -415,6 +415,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
||||
x.imageUrl,
|
||||
width: 28,
|
||||
height: 28,
|
||||
isDense: true,
|
||||
),
|
||||
display: x.name,
|
||||
content: x.textWarpedPlaceholder,
|
||||
|
@ -14,12 +14,14 @@ class MarkdownTextContent extends StatelessWidget {
|
||||
final String content;
|
||||
final String parentId;
|
||||
final bool isSelectable;
|
||||
final bool isLargeText;
|
||||
|
||||
const MarkdownTextContent({
|
||||
super.key,
|
||||
required this.content,
|
||||
required this.parentId,
|
||||
this.isSelectable = false,
|
||||
this.isLargeText = false,
|
||||
});
|
||||
|
||||
Widget _buildContent(BuildContext context) {
|
||||
@ -35,6 +37,14 @@ class MarkdownTextContent extends StatelessWidget {
|
||||
styleSheet: MarkdownStyleSheet.fromTheme(
|
||||
Theme.of(context),
|
||||
).copyWith(
|
||||
textScaleFactor: isLargeText ? 1.1 : 1,
|
||||
blockquote: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
blockquoteDecoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||
),
|
||||
horizontalRuleDecoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
|
@ -341,64 +341,67 @@ class _PostItemState extends State<PostItem> {
|
||||
if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: Column(
|
||||
children: snapshot.data!
|
||||
.map(
|
||||
(x) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AccountAvatar(content: x.author.avatar, radius: 10),
|
||||
const Gap(6),
|
||||
Text(
|
||||
x.author.nick,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Gap(6),
|
||||
Text(
|
||||
format(
|
||||
x.publishedAt?.toLocal() ?? DateTime.now(),
|
||||
locale: 'en_short',
|
||||
return Container(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: Card(
|
||||
margin: EdgeInsets.zero,
|
||||
child: Column(
|
||||
children: snapshot.data!
|
||||
.map(
|
||||
(x) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AccountAvatar(content: x.author.avatar, radius: 10),
|
||||
const Gap(6),
|
||||
Text(
|
||||
x.author.nick,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
).paddingOnly(top: 0.5),
|
||||
const Gap(8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MarkdownTextContent(
|
||||
content: x.body['content'],
|
||||
parentId: 'p${item.id}-featured-reply${x.id}',
|
||||
),
|
||||
if (x.body['attachments'] is List &&
|
||||
x.body['attachments'].length > 0)
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.file_copy,
|
||||
size: 15,
|
||||
color: unFocusColor,
|
||||
).paddingOnly(right: 5),
|
||||
Text(
|
||||
'attachmentHint'.trParams(
|
||||
{
|
||||
'count': x.body['attachments'].length
|
||||
.toString()
|
||||
},
|
||||
),
|
||||
style: TextStyle(color: unFocusColor),
|
||||
)
|
||||
],
|
||||
const Gap(6),
|
||||
Text(
|
||||
format(
|
||||
x.publishedAt?.toLocal() ?? DateTime.now(),
|
||||
locale: 'en_short',
|
||||
),
|
||||
).paddingOnly(top: 0.5),
|
||||
const Gap(8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MarkdownTextContent(
|
||||
content: x.body['content'],
|
||||
parentId: 'p${item.id}-featured-reply${x.id}',
|
||||
),
|
||||
],
|
||||
if (x.body['attachments'] is List &&
|
||||
x.body['attachments'].length > 0)
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.file_copy,
|
||||
size: 15,
|
||||
color: unFocusColor,
|
||||
).paddingOnly(right: 5),
|
||||
Text(
|
||||
'attachmentHint'.trParams(
|
||||
{
|
||||
'count': x.body['attachments'].length
|
||||
.toString()
|
||||
},
|
||||
),
|
||||
style: TextStyle(color: unFocusColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).paddingSymmetric(horizontal: 12, vertical: 8),
|
||||
)
|
||||
.toList(),
|
||||
],
|
||||
).paddingSymmetric(horizontal: 12, vertical: 8),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
)
|
||||
.animate()
|
||||
@ -550,6 +553,8 @@ class _PostItemState extends State<PostItem> {
|
||||
parentId: 'p${item.id}-embed',
|
||||
content: item.body['content'],
|
||||
isSelectable: widget.isContentSelectable,
|
||||
isLargeText: item.type == 'article' &&
|
||||
widget.isFullContent,
|
||||
).paddingOnly(left: 12, right: 8),
|
||||
),
|
||||
),
|
||||
|
@ -21,19 +21,19 @@ PODS:
|
||||
- Firebase/Messaging (11.0.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 11.0.0)
|
||||
- firebase_analytics (11.3.1):
|
||||
- firebase_analytics (11.3.2):
|
||||
- Firebase/Analytics (= 11.0.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_core (3.4.1):
|
||||
- firebase_core (3.5.0):
|
||||
- Firebase/CoreOnly (~> 11.0.0)
|
||||
- FlutterMacOS
|
||||
- firebase_crashlytics (4.1.1):
|
||||
- firebase_crashlytics (4.1.2):
|
||||
- Firebase/CoreOnly (~> 11.0.0)
|
||||
- Firebase/Crashlytics (~> 11.0.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_messaging (15.1.1):
|
||||
- firebase_messaging (15.1.2):
|
||||
- Firebase/CoreOnly (~> 11.0.0)
|
||||
- Firebase/Messaging (~> 11.0.0)
|
||||
- firebase_core
|
||||
@ -338,10 +338,10 @@ SPEC CHECKSUMS:
|
||||
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
|
||||
file_selector_macos: 54fdab7caa3ac3fc43c9fac4d7d8d231277f8cf2
|
||||
Firebase: 9f574c08c2396885b5e7e100ed4293d956218af9
|
||||
firebase_analytics: 2169e28bb3ee1f765efe0fd4f5b5f625d92fda13
|
||||
firebase_core: 3f80bec72646b26618f0497e74ce8bcd608f03ca
|
||||
firebase_crashlytics: 6b1e511297406a6efd4405dc6301da8843b9dfe1
|
||||
firebase_messaging: ce70e6615f0cd906d80b7a651b960d76dad6de56
|
||||
firebase_analytics: a2d0d907566e4a48e27745317f05b4b7db85edd9
|
||||
firebase_core: c55630cdb8a01cf49eae741dd4bc8c93bdd546b8
|
||||
firebase_crashlytics: a359f1f75a23e560c8c97b743ab684ba795d7688
|
||||
firebase_messaging: 12726b352752420d073ff075e328cc2f0ca14c47
|
||||
FirebaseAnalytics: 27eb78b97880ea4a004839b9bac0b58880f5a92a
|
||||
FirebaseCore: 3cf438f431f18c12cdf2aaf64434648b63f7e383
|
||||
FirebaseCoreExtension: cda74ddfb001224bd8fd1d6e74698b4ed07803de
|
||||
|
76
pubspec.lock
76
pubspec.lock
@ -13,10 +13,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
sha256: ddc6f775260b89176d329dee26f88b9469ef46aa3228ff6a0b91caf2b2989692
|
||||
sha256: "5fdcea390499dd26c808a3c662df5f4208d6bbc0643072eee94f1476249e2818"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.42"
|
||||
version: "1.3.43"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
@ -490,114 +490,114 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_analytics
|
||||
sha256: "7b5ae39d853ead76f9d030dc23389bfec4ea826d7cccb4eea4873dcb0cdd172b"
|
||||
sha256: "9c52c099e9cbb852c7f1d2302c7eb34a15758834eca1877f7a779e6082f9882d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.3.1"
|
||||
version: "11.3.2"
|
||||
firebase_analytics_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_analytics_platform_interface
|
||||
sha256: "0205e05bb37abd29d5dec5cd89aeb04f3f58bf849aad21dd938be0507d52a40c"
|
||||
sha256: "4ec57aee951832fdbf10ca722bbb83fe0001d6168d6c4cfea9ccee0df6afb1e0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.3"
|
||||
version: "4.2.4"
|
||||
firebase_analytics_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_analytics_web
|
||||
sha256: "434807f8b30526e21cc062410c28ee5c6680a13626c4443b5ffede29f84b0c74"
|
||||
sha256: "95c594fb1e8960992a607b135459e2f9ea3683dd8d01e6b845cace7c6665ec7e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.10"
|
||||
version: "0.5.10+1"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
sha256: "40921de9795fbf5887ed5c0adfdf4972d5a8d7ae7e1b2bb98dea39bc02626a88"
|
||||
sha256: c7de9354eb2cd8bfe8059e1112174c9a58beda7051807207306bc48283277cfb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
version: "3.5.0"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
sha256: f7d7180c7f99babd4b4c517754d41a09a4943a0f7a69b65c894ca5c68ba66315
|
||||
sha256: e30da58198a6d4b49d5bce4e852f985c32cb10db329ebef9473db2b9f09ce810
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.2.1"
|
||||
version: "5.3.0"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: f4ee170441ca141c5f9ee5ad8737daba3ee9c8e7efb6902aee90b4fbd178ce25
|
||||
sha256: f967a7138f5d2ffb1ce15950e2a382924239eaa521150a8f144af34e68b3b3e5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.18.0"
|
||||
version: "2.18.1"
|
||||
firebase_crashlytics:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_crashlytics
|
||||
sha256: c4fdbb14ba6f36794f89dc27fb5c759c9cc67ecbaeb079edc4dba515bbf9f555
|
||||
sha256: "7821f9d8373b91f2a5ca8214226891d5870e196a7376f66350f65204387e9c15"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
version: "4.1.2"
|
||||
firebase_crashlytics_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_crashlytics_platform_interface
|
||||
sha256: "891d6f7ba4b93672d0e1265f27b6a9dccd56ba2cc30ce6496586b32d1d8770ac"
|
||||
sha256: "8ed539fd9e9b6c07905f9f44c5f6d4785ac841a5a8195bd35586c8b1d54ec26d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.6.42"
|
||||
version: "3.6.43"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
sha256: cc02c4afd6510cd84586020670140c4a23fbe52af16cd260ccf8ede101bb8d1b
|
||||
sha256: "32ce60b747e755b48d7112d728d4f736ba82acd98ec825626558d444d385fa3a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.1.1"
|
||||
version: "15.1.2"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
sha256: d8a4984635f09213302243ea670fe5c42f3261d7d8c7c0a5f7dcd5d6c84be459
|
||||
sha256: "69671a0f1a40c7b7c46ad0283e6f34ca2a59a0362ca14a240a4ea01c46e8a521"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.44"
|
||||
version: "4.5.45"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
sha256: "258b9d637965db7855299b123533609ed95e52350746a723dfd1d8d6f3fac678"
|
||||
sha256: "6890111a9d01d7b13d0f6fe74850812c334e903d2c80a2d9356a3abb8c3a9e9a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.9.0"
|
||||
version: "3.9.1"
|
||||
firebase_performance:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_performance
|
||||
sha256: "879ce4d83242cb7d1ec67a8b45daa351f230211778e34eeea979894839c4832a"
|
||||
sha256: ed9a408b6d1f221fc0e2890dcf0733b604d1aea6cd3b897f97dd3f889f01ddfc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.0+6"
|
||||
version: "0.10.0+7"
|
||||
firebase_performance_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_performance_platform_interface
|
||||
sha256: ac68eba644f593903a931ba7f26f0677b725d5a60f8f7bc0fed01d88a11d1463
|
||||
sha256: bfcfbfcefeaf3853a72602675b786e13a609d49ac70fc325d302b5794b8b0c06
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.4+42"
|
||||
version: "0.1.4+43"
|
||||
firebase_performance_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_performance_web
|
||||
sha256: ff53b9c5d8601fc983d0173b88fdfd8abcc74948f0a3753f3c1ec276b680f23c
|
||||
sha256: "2ac9e44a1be7b20f1a7a3912d84bf2e1ec76398f2dadc07b6b7c3173d590e329"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.7"
|
||||
version: "0.1.7+1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -635,6 +635,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.0"
|
||||
flutter_app_update:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_app_update
|
||||
sha256: "2b83278d5cc807f543e623d5b466216316104335a4918d9cc4556f39985fe84a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
flutter_background_service:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -2130,6 +2138,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: version
|
||||
sha256: "3d4140128e6ea10d83da32fef2fa4003fccbf6852217bb854845802f04191f94"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
very_good_infinite_list:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -2,7 +2,7 @@ name: solian
|
||||
description: "The Solar Network App"
|
||||
publish_to: "none"
|
||||
|
||||
version: 1.2.1+40
|
||||
version: 1.2.2+2
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.4 <4.0.0"
|
||||
@ -80,6 +80,8 @@ dependencies:
|
||||
path_provider: ^2.1.4
|
||||
flutter_background_service: ^5.0.10
|
||||
flutter_local_notifications: ^17.2.2
|
||||
flutter_app_update: ^3.1.0
|
||||
version: ^3.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Reference in New Issue
Block a user