diff --git a/assets/locales/en_us.json b/assets/locales/en_us.json index feae397..a7640e6 100644 --- a/assets/locales/en_us.json +++ b/assets/locales/en_us.json @@ -373,7 +373,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", diff --git a/assets/locales/zh_cn.json b/assets/locales/zh_cn.json index b8c4d41..e5f73af 100644 --- a/assets/locales/zh_cn.json +++ b/assets/locales/zh_cn.json @@ -374,7 +374,8 @@ "callStatusReconnected": "重连中", "messageOutOfSync": "消息可能与服务器脱节", "messageOutOfSyncCaption": "由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。", - "messageHistoryWipe": "清除消息记录", + "localDatabaseWipe": "清除本地数据库", + "localDatabaseSize": "本地数据库大小:@size", "unknown": "未知", "collapse": "折叠", "expand": "展开", diff --git a/lib/exts.dart b/lib/exts.dart index 27abdb6..aad3f1f 100644 --- a/lib/exts.dart +++ b/lib/exts.dart @@ -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]}'; + } +} diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart index 840ce67..6dcf0c0 100644 --- a/lib/providers/auth.dart +++ b/lib/providers/auth.dart @@ -8,6 +8,7 @@ import 'package:get/get.dart'; import 'package:get/get_connect/http/src/request/request.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 +199,8 @@ class AuthProvider extends GetConnect { Get.find().notifications.clear(); Get.find().notificationUnread.value = 0; + AppDatabase.removeDatabase(); + storage.deleteAll(); } diff --git a/lib/providers/database/database.dart b/lib/providers/database/database.dart index 3ee3795..3495fa5 100644 --- a/lib/providers/database/database.dart +++ b/lib/providers/database/database.dart @@ -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 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 removeDatabase() async { + if (PlatformInfo.isWeb) return; + final basepath = await getApplicationDocumentsDirectory(); + final file = File(join(basepath.path, 'solar_network_local_db.sqlite')); + await Get.find().database.close(); + await file.delete(); + Get.find().database = AppDatabase(); + } } class DatabaseProvider extends GetxController { - final database = AppDatabase(); + var database = AppDatabase(); } diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 4621c21..b2bf35c 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -3,6 +3,7 @@ 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/providers/database/database.dart'; import 'package:solian/providers/theme_switcher.dart'; import 'package:solian/router.dart'; import 'package:solian/theme.dart'; @@ -81,6 +82,30 @@ class _SettingScreenState extends State { ).paddingSymmetric(horizontal: 12, vertical: 8), ), _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 +115,6 @@ class _SettingScreenState extends State { 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 - }, - ), ], ), ); diff --git a/lib/widgets/attachments/attachment_editor.dart b/lib/widgets/attachments/attachment_editor.dart index a297455..f8eb736 100644 --- a/lib/widgets/attachments/attachment_editor.dart +++ b/lib/widgets/attachments/attachment_editor.dart @@ -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 { }); } - 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 { 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 { ), ), Text( - '${fileType[0].toUpperCase()}${fileType.substring(1)} · ${_formatBytes(element.size)}', + '${fileType[0].toUpperCase()}${fileType.substring(1)} · ${element.size.formatBytes()}', style: const TextStyle(fontSize: 12), ), ], diff --git a/lib/widgets/attachments/attachment_fullscreen.dart b/lib/widgets/attachments/attachment_fullscreen.dart index d529703..810f8aa 100644 --- a/lib/widgets/attachments/attachment_fullscreen.dart +++ b/lib/widgets/attachments/attachment_fullscreen.dart @@ -38,25 +38,6 @@ class _AttachmentFullScreenState extends State { 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 { style: metaTextStyle, ), Text( - _formatBytes(widget.item.size), + widget.item.size.formatBytes(), style: metaTextStyle, ), Text( diff --git a/lib/widgets/attachments/attachment_item.dart b/lib/widgets/attachments/attachment_item.dart index 3c0af8a..f87e82c 100644 --- a/lib/widgets/attachments/attachment_item.dart +++ b/lib/widgets/attachments/attachment_item.dart @@ -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, diff --git a/pubspec.lock b/pubspec.lock index 8ee01ff..5be538d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1366,7 +1366,7 @@ packages: source: hosted version: "1.0.1" path_provider: - dependency: transitive + dependency: "direct main" description: name: path_provider sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 diff --git a/pubspec.yaml b/pubspec.yaml index 6202d52..3626806 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -78,6 +78,7 @@ dependencies: drift: ^2.20.2 drift_flutter: ^0.2.0 very_good_infinite_list: ^0.8.0 + path_provider: ^2.1.4 dev_dependencies: flutter_test: