diff --git a/lib/l10n/app_ja-oj.arb b/lib/l10n/app_ja-oj.arb index bac68a8d4..5e929fe69 100644 --- a/lib/l10n/app_ja-oj.arb +++ b/lib/l10n/app_ja-oj.arb @@ -106,6 +106,9 @@ "cannotMentionToRemoteInLocalOnlyNote": "連合切られているのに他のサーバーの人がメンションに含まれているようですわ", "cannotPublicReplyToPrivateNote": "リプライが{visibility}のようでして……パブリックにはできませんこと", + "cache": "キャッシュ", + "clearCache": "キャッシュとお別れいたしますわ", + "unsupportedFile": "対応してないファイルのようですわ", "failedFileSave": "ファイルの保存に失敗したようですわね…" diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 55369c6e0..b234cd00b 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -826,6 +826,9 @@ "fontSize": "フォントサイズ", "systemFont": "システム標準", + "cache": "キャッシュ", + "clearCache": "キャッシュをクリア", + "selectFolder": "フォルダー選択", "settingsFileManagement": "設定ファイルの管理", "importAndExportSettingsDescription": "現在の設定から、アカウントのログイン情報を除くすべての設定を設定ファイルに出力して管理することができます。設定ファイルは、指定したアカウントの「ドライブ」内に保存されます。", diff --git a/lib/l10n/app_zh-cn.arb b/lib/l10n/app_zh-cn.arb index 0e7bda852..6c6572212 100644 --- a/lib/l10n/app_zh-cn.arb +++ b/lib/l10n/app_zh-cn.arb @@ -773,6 +773,8 @@ "fontFantasy": "字体 (适用于 $[font.fantasy )", "fontSize": "字体大小", "systemFont": "系统标准", + "cache": "快取", + "clearCache": "清除快取", "selectFolder": "选择文件夹", "importSettings": "导入设置", "importSettingsDescription": "从驱动器加载配置文件。配置文件保存时会记录所有账号的配置信息,但只会加载登录本设备的账号的信息。", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 0e7bda852..6c6572212 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -773,6 +773,8 @@ "fontFantasy": "字体 (适用于 $[font.fantasy )", "fontSize": "字体大小", "systemFont": "系统标准", + "cache": "快取", + "clearCache": "清除快取", "selectFolder": "选择文件夹", "importSettings": "导入设置", "importSettingsDescription": "从驱动器加载配置文件。配置文件保存时会记录所有账号的配置信息,但只会加载登录本设备的账号的信息。", diff --git a/lib/util/cache_size.dart b/lib/util/cache_size.dart new file mode 100644 index 000000000..1eb543e81 --- /dev/null +++ b/lib/util/cache_size.dart @@ -0,0 +1,68 @@ +import "dart:io"; +import "dart:math"; +import "package:path_provider/path_provider.dart"; + +/// 単位付きのキャッシュサイズを取得する +Future getCacheSizeWithUnit() async { + const unitArr = ["Byte", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + + // キャッシュサイズ + final cacheSizeByte = await _getCacheSizeByte(); + + // 単位 + final unitIndex = (cacheSizeByte.toString().length / 3).ceil() - 1; + final unit = unitArr[unitIndex]; + + // "00.0 GB"の形にする + final cacheSizeStr = (cacheSizeByte / pow(1000, unitIndex)).toStringAsFixed(1); + + return "$cacheSizeStr $unit"; +} + +/// キャッシュをクリアする +Future clearCache() async { + // 画像キャッシュ格納ディレクトリを削除 + final cacheDir = await _getLibCachedImageDataDir(); + if (await cacheDir.exists()){ + // ディレクトリが存在する場合のみ実行(ボタン連打対策) + await cacheDir.delete(recursive: true); + } + final cacheSizeStr = await getCacheSizeWithUnit(); + + // キャッシュクリア後のキャッシュサイズを返す("0.0 Byte"のはず) + return cacheSizeStr; +} + +/// キャッシュサイズを取得する +Future _getCacheSizeByte() async { + // キャッシュ格納ディレクトリを取得して + // 中身のファイルサイズを全て合計 + final cacheDir = await _getLibCachedImageDataDir(); + final cacheSize = await _getDirSize(cacheDir); + + return cacheSize; +} + +/// ディレクトリ配下のファイルサイズ合計を取得する +Future _getDirSize(Directory dir) async { + // ディレクトリが存在しない場合は0を返却 + if (!(await dir.exists())) { + return 0; + } + + // dir配下のファイル・ディレクトリをすべて取得してファイルサイズの合計を取得 + final dirSize = dir + .list(recursive: true) + .fold(0, (prev, element) => prev + element.statSync().size); + + return dirSize; +} + +/// libCachedImageDataのパスを取得する +Future _getLibCachedImageDataDir() async { + const libCachedImageDataPath = "libCachedImageData"; + final tempDir = await getTemporaryDirectory(); + final libCachedImageDataDir = Directory("${tempDir.path}/$libCachedImageDataPath"); + + return libCachedImageDataDir; +} diff --git a/lib/view/settings_page/general_settings_page/general_settings_page.dart b/lib/view/settings_page/general_settings_page/general_settings_page.dart index b71a61677..db150a6fe 100644 --- a/lib/view/settings_page/general_settings_page/general_settings_page.dart +++ b/lib/view/settings_page/general_settings_page/general_settings_page.dart @@ -1,4 +1,5 @@ import "dart:async"; +import "dart:io"; import "package:auto_route/auto_route.dart"; import "package:collection/collection.dart"; @@ -9,6 +10,7 @@ import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:miria/const.dart"; import "package:miria/model/general_settings.dart"; import "package:miria/providers.dart"; +import "package:miria/util/cache_size.dart"; import "package:miria/view/themes/built_in_color_themes.dart"; @RoutePage() @@ -39,6 +41,7 @@ class GeneralSettingsPage extends HookConsumerWidget { final fantasyFontName = useState(settings.fantasyFontName); final language = useState(settings.languages); final isDeckMode = useState(settings.isDeckMode); + final cacheSize = useState(""); useMemoized(() { if (lightModeTheme.value.isEmpty) { @@ -109,6 +112,17 @@ class GeneralSettingsPage extends HookConsumerWidget { useMemoized(() => unawaited(save()), dependencies); + // キャッシュサイズ表示 + final getCacheSize = useMemoized(() => (){ + WidgetsBinding.instance.addPostFrameCallback((_) async { + cacheSize.value = await getCacheSizeWithUnit(); + }); + },); + useEffect(() { + getCacheSize(); + return null; + }, [],); + return Scaffold( appBar: AppBar(title: Text(S.of(context).generalSettings)), body: SingleChildScrollView( @@ -487,6 +501,39 @@ class GeneralSettingsPage extends HookConsumerWidget { ), ), ), + Card( + child: Padding( + padding: const EdgeInsets.all(15), + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + S.of(context).cache, + style: Theme.of(context).textTheme.titleLarge, + ), + ListTile( + title: (cacheSize.value != "") + ? Text(cacheSize.value) + : const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [CircularProgressIndicator()], + ), + trailing: ElevatedButton( + onPressed: (cacheSize.value != "") + ? () async { + cacheSize.value = ""; + cacheSize.value = await clearCache(); + } + : null, + child: Text(S.of(context).clearCache), + ), + ), + ], + ), + ), + ), ], ), ),