refa: cache manager (#2266)

* opt: image utils

* refa: cache manager
This commit is contained in:
My-Responsitories
2026-06-02 14:09:36 +00:00
committed by dom
parent 2c775e6d19
commit 95efeec147
26 changed files with 124 additions and 198 deletions

View File

@@ -2,10 +2,10 @@
import 'dart:developer' show log;
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CachedNetworkSVGImage extends StatefulWidget {
@@ -28,7 +28,7 @@ class CachedNetworkSVGImage extends StatefulWidget {
this._colorFilter,
this._placeholderBuilder,
BaseCacheManager? cacheManager,
}) : _cacheManager = cacheManager ?? DefaultCacheManager(),
}) : _cacheManager = cacheManager ?? DefaultCacheManager.instance!,
super(key: key ?? ValueKey(_cacheKey ?? _url));
final String _url;

View File

@@ -2,7 +2,7 @@ import 'package:PiliPlus/common/assets.dart';
import 'package:PiliPlus/common/style.dart';
import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
class NetworkImgLayer extends StatelessWidget {
@@ -79,7 +79,7 @@ class NetworkImgLayer extends StatelessWidget {
placeholder: (_, _) =>
getPlaceHolder?.call() ??
_placeholder(context, isEmote: isEmote, isAvatar: isAvatar),
errorWidget: (_, _, _) =>
errorBuilder: (_, _, _) =>
_placeholder(context, isEmote: isEmote, isAvatar: isAvatar),
);
}

View File

@@ -35,7 +35,7 @@ import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:PiliPlus/utils/theme_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart' hide Image, PageView;

View File

@@ -94,7 +94,11 @@ void main() async {
if (kDebugMode) debugPrint('GStorage init error: $e');
exit(0);
}
await Future.wait([_initDownPath(), _initTmpPath()]);
await Future.wait([
_initDownPath(),
_initTmpPath(),
CacheManager.ensureInitialized(),
]);
Get
..lazyPut(AccountService.new)
..lazyPut(DownloadService.new);

View File

@@ -23,7 +23,7 @@ import 'package:PiliPlus/utils/num_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/share_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

View File

@@ -5,7 +5,7 @@ import 'package:PiliPlus/models_new/article/article_view/ops.dart';
import 'package:PiliPlus/pages/dynamics/widgets/vote.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

View File

@@ -3,7 +3,7 @@ import 'package:PiliPlus/common/widgets/image_viewer/hero.dart';
import 'package:PiliPlus/models/common/image_preview_type.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';

View File

@@ -16,7 +16,7 @@ import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/extension/theme_ext.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';
import 'package:get/get_core/src/get_main.dart';

View File

@@ -19,13 +19,12 @@ import 'package:PiliPlus/utils/extension/theme_ext.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:dio/dio.dart' show CancelToken;
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:image_cropper/image_cropper.dart';
@@ -189,11 +188,10 @@ abstract class CommonRichTextPubPageState<T extends CommonRichTextPubPage>
path = e.path;
case OpusPicModel e:
SmartDialog.showLoading();
final file = (await DefaultCacheManager().getSingleFile(
path = (await DefaultCacheManager.instance!.getSingleFile(
e.url.http2https,
));
)).path;
await SmartDialog.dismiss();
path = file.path;
}
if (!mounted || path.isEmpty) return;
late final colorScheme = ColorScheme.of(context);

View File

@@ -23,7 +23,7 @@ import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/request_utils.dart';
import 'package:PiliPlus/utils/share_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';

View File

@@ -13,7 +13,7 @@ import 'package:PiliPlus/pages/dynamics/widgets/video_panel.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

View File

@@ -8,7 +8,7 @@ import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';
import 'package:get/get.dart';

View File

@@ -43,7 +43,7 @@ import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/theme_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:canvas_danmaku/canvas_danmaku.dart';
import 'package:flutter/foundation.dart' show kDebugMode, clampDouble;
import 'package:flutter/material.dart' hide PageView;

View File

@@ -41,9 +41,9 @@ import 'package:PiliPlus/utils/num_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
@@ -701,7 +701,7 @@ class _MemberPageState extends State<MemberPage> {
Future<void> _createShortcutAndroid() async {
try {
SmartDialog.showLoading();
final file = (await DefaultCacheManager().getSingleFile(
final file = (await DefaultCacheManager.instance!.getSingleFile(
'${_userController.userAvatar!}@200w_200h.webp'.http2https,
));
SmartDialog.dismiss();

View File

@@ -34,7 +34,7 @@ import 'package:PiliPlus/utils/num_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';

View File

@@ -2,7 +2,7 @@ import 'package:PiliPlus/common/assets.dart';
import 'package:PiliPlus/models_new/search/search_trending/list.dart';
import 'package:PiliPlus/utils/extension/string_ext.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'
show

View File

@@ -13,7 +13,7 @@ import 'package:PiliPlus/utils/extension/context_ext.dart';
import 'package:PiliPlus/utils/extension/get_ext.dart';
import 'package:PiliPlus/utils/extension/size_ext.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart' show clampDouble;
import 'package:flutter/material.dart' hide ListTile;
import 'package:flutter/services.dart' show SystemUiOverlayStyle;

View File

@@ -35,7 +35,7 @@ import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/url_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:flutter/material.dart';

View File

@@ -18,7 +18,7 @@ import 'package:PiliPlus/utils/duration_utils.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';

View File

@@ -51,12 +51,12 @@ import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/foundation.dart' show clampDouble, kDebugMode;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

View File

@@ -102,7 +102,7 @@ class VideoShotImage extends StatefulWidget {
}
Future<ui.Image?> _getImg(String url) async {
final cacheManager = DefaultCacheManager();
final cacheManager = DefaultCacheManager.instance!;
final cacheKey = Utils.getFileName(url, fileExt: false);
try {
final fileInfo = await cacheManager.getSingleFile(

View File

@@ -19,9 +19,9 @@ import 'package:PiliPlus/utils/extension/file_ext.dart';
import 'package:PiliPlus/utils/extension/string_ext.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/path_utils.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/foundation.dart'
show kDebugMode, debugPrint, VoidCallback;
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
show kDebugMode, debugPrint, VoidCallbackebugPrint, VoidCallback;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as path;
@@ -350,7 +350,7 @@ class DownloadService extends GetxService {
if (File(filePath).existsSync()) {
return true;
}
final file = (await DefaultCacheManager().getFileFromCache(
final file = (await DefaultCacheManager.instance!.getFileFromCache(
entry.cover,
))?.file;
if (file != null) {

View File

@@ -1,27 +1,29 @@
import 'dart:io' show Directory, File;
import 'package:PiliPlus/utils/extension/file_ext.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
abstract final class CacheManager {
static late final DefaultCacheManager manager;
static Future<void> ensureInitialized() =>
DefaultCacheManager.init().then((i) => manager = i);
// 获取缓存目录
@pragma('vm:notify-debugger-on-exception')
static Future<int> loadApplicationCache([
final num maxSize = double.infinity,
]) async {
static Future<int> loadApplicationCache() async {
try {
final Directory tempDirectory = await getTemporaryDirectory();
if (PlatformUtils.isDesktop) {
final dir = Directory('${tempDirectory.path}/libCachedImageData');
if (dir.existsSync()) {
return await getTotalSizeOfFilesInDir(dir, maxSize);
}
return 0;
return manager.getTotalLength();
}
if (tempDirectory.existsSync()) {
return await getTotalSizeOfFilesInDir(tempDirectory, maxSize);
return await getTotalSizeOfFilesInDir(tempDirectory);
}
} catch (_) {}
return 0;
@@ -29,32 +31,34 @@ abstract final class CacheManager {
// 循环计算文件的大小
@pragma('vm:notify-debugger-on-exception')
static Future<int> getTotalSizeOfFilesInDir(
final Directory file, [
final num maxSize = double.infinity,
]) async {
final children = file.list(recursive: true);
static Future<int> getTotalSizeOfFilesInDir(final Directory file) async {
int total = 0;
await for (final child in children) {
await for (final child in file.list(recursive: false)) {
if (child is File) {
total += await child.length();
if (total >= maxSize) break;
} else if (child is Directory) {
if (path.equals(child.path, manager.cacheDir)) {
total += manager.getTotalLength();
} else {
await for (final i in child.list(recursive: true)) {
if (i is File) {
total += await i.length();
}
}
}
}
}
return total;
}
// 清除 Library/Caches 目录及文件缓存
@pragma('vm:notify-debugger-on-exception')
static Future<void> clearLibraryCache() async {
try {
final Directory tempDirectory = await getTemporaryDirectory();
if (PlatformUtils.isDesktop) {
final dir = Directory('${tempDirectory.path}/libCachedImageData');
if (dir.existsSync()) {
await dir.delete(recursive: true);
}
return;
}
await manager.emptyCache();
if (PlatformUtils.isDesktop) return;
final tempDirectory = await getTemporaryDirectory();
if (tempDirectory.existsSync()) {
final children = tempDirectory.list(recursive: false);
await for (final file in children) {
@@ -65,9 +69,13 @@ abstract final class CacheManager {
}
static Future<void> autoClearCache() async {
// TODO: remove
Directory(
'${(await getTemporaryDirectory()).path}/libCachedImageData',
).tryDel(recursive: true);
final maxCacheSize = Pref.maxCacheSize;
if (maxCacheSize != 0) {
final currCache = await loadApplicationCache(maxCacheSize);
final currCache = await loadApplicationCache();
if (currCache >= maxCacheSize) {
await clearLibraryCache();
}

View File

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:io' show File, Platform;
import 'dart:math' as math;
import 'dart:typed_data' show Uint8List;
@@ -13,10 +14,10 @@ import 'package:PiliPlus/utils/permission_handler.dart';
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/share_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:dio/dio.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:intl/intl.dart' show DateFormat;
import 'package:live_photo_maker/live_photo_maker.dart';
@@ -34,19 +35,16 @@ abstract final class ImageUtils {
static Future<void> onShareImg(String url) async {
try {
SmartDialog.showLoading();
final path = '$tmpDirPath/${Utils.getFileName(url)}';
final res = await Request.downloadFile(url.http2https, path);
final res = await DefaultCacheManager.instance!.getSingleFile(
url.http2https,
);
SmartDialog.dismiss();
if (res.statusCode == 200) {
await SharePlus.instance
.share(
ShareParams(
files: [XFile(path)],
sharePositionOrigin: await ShareUtils.sharePositionOrigin,
),
)
.whenComplete(File(path).tryDel);
}
await SharePlus.instance.share(
ShareParams(
files: [XFile(res.path)],
sharePositionOrigin: await ShareUtils.sharePositionOrigin,
),
);
} catch (e) {
SmartDialog.showToast(e.toString());
}
@@ -80,12 +78,12 @@ abstract final class ImageUtils {
}
}
static Future<bool> checkPermissionDependOnSdkInt() {
static FutureOr<bool> checkPermissionDependOnSdkInt() {
if (Platform.isAndroid) {
if (DeviceUtils.sdkInt < 29) {
return requestPer();
} else {
return Future.syncValue(true);
return true;
}
}
return requestPer();
@@ -103,8 +101,6 @@ abstract final class ImageUtils {
}
SmartDialog.showLoading(msg: '正在下载');
late String imageName = "cover_${Utils.getFileName(url)}";
late String imagePath = '$tmpDirPath/$imageName';
String videoName = "video_${Utils.getFileName(liveUrl)}";
String videoPath = '$tmpDirPath/$videoName';
@@ -112,22 +108,17 @@ abstract final class ImageUtils {
if (res.statusCode != 200) throw '${res.statusCode}';
if (Platform.isIOS) {
final res1 = await Request.downloadFile(url.http2https, imagePath);
if (res1.statusCode != 200) throw '${res1.statusCode}';
final imageFile = await DefaultCacheManager.instance!.getSingleFile(
url.http2https,
);
SmartDialog.showLoading(msg: '正在保存');
bool success =
await LivePhotoMaker.create(
coverImage: imagePath,
imagePath: null,
voicePath: videoPath,
width: width,
height: height,
).whenComplete(
() {
File(videoPath).tryDel();
File(imagePath).tryDel();
},
);
bool success = await LivePhotoMaker.create(
coverImage: imageFile.path,
imagePath: null,
voicePath: videoPath,
width: width,
height: height,
).whenComplete(File(videoPath).tryDel);
if (success) {
SmartDialog.showToast(' 已保存 ');
} else {
@@ -152,10 +143,7 @@ abstract final class ImageUtils {
}
}
static Future<bool> downloadImg(
List<String> imgList, [
CacheManager? manager,
]) async {
static Future<bool> downloadImg(List<String> imgList) async {
if (PlatformUtils.isMobile && !await checkPermissionDependOnSdkInt()) {
return false;
}
@@ -169,32 +157,10 @@ abstract final class ImageUtils {
try {
final futures = imgList.map((url) async {
final name = Utils.getFileName(url);
final file = (await (manager ?? DefaultCacheManager()).getFileFromCache(
final file = await DefaultCacheManager.instance!.getSingleFile(
url.http2https,
))?.file;
if (file == null) {
final String filePath = '$tmpDirPath/$name';
final response = await Request.downloadFile(
url.http2https,
filePath,
cancelToken: cancelToken,
);
return (
filePath: filePath,
name: name,
statusCode: response.statusCode,
del: true,
);
} else {
return (
filePath: file.path,
name: name,
statusCode: 200,
del: false,
);
}
);
return (filePath: file.path, name: name, statusCode: 200);
});
final result = await Future.wait(futures, eagerError: true);
bool success = true;
@@ -202,7 +168,6 @@ abstract final class ImageUtils {
final delList = <String>[];
final saveList = <SaveFileData>[];
for (final i in result) {
if (i.del) delList.add(i.filePath);
if (i.statusCode == 200) {
saveList.add(
SaveFileData(
@@ -222,11 +187,7 @@ abstract final class ImageUtils {
} else {
for (final res in result) {
if (res.statusCode == 200) {
await saveFileImg(
filePath: res.filePath,
fileName: res.name,
del: res.del,
);
await saveFileImg(filePath: res.filePath, fileName: res.name);
} else {
success = false;
}
@@ -340,7 +301,6 @@ abstract final class ImageUtils {
required String fileName,
FileType type = FileType.image,
bool needToast = false,
bool del = true,
}) async {
final file = File(filePath);
if (!file.existsSync()) {
@@ -355,7 +315,6 @@ abstract final class ImageUtils {
albumPath: _albumPath,
skipIfExists: false,
);
if (del) file.tryDel();
} else {
final savePath = await FilePicker.saveFile(
type: type,
@@ -367,7 +326,6 @@ abstract final class ImageUtils {
return;
}
await file.copy(savePath);
if (del) file.tryDel();
res = SaveResult(true, null);
}
if (needToast) {