diff --git a/lib/common/widgets/image_grid/image_grid_view.dart b/lib/common/widgets/image_grid/image_grid_view.dart index d58a43ed0..6db266ef3 100644 --- a/lib/common/widgets/image_grid/image_grid_view.dart +++ b/lib/common/widgets/image_grid/image_grid_view.dart @@ -24,6 +24,7 @@ import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image_grid/image_grid_builder.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/utils/extension/context_ext.dart'; +import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/extension/size_ext.dart'; import 'package:PiliPlus/utils/image_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; @@ -40,6 +41,7 @@ class ImageModel { required num? height, required this.url, this.liveUrl, + this.size, }) { this.width = width == null || width == 0 ? 1 : width; this.height = height == null || height == 0 ? 1 : height; @@ -51,6 +53,7 @@ class ImageModel { String? liveUrl; bool? _isLongPic; bool? _isLivePhoto; + num? size; bool get isLongPic => _isLongPic ??= (height / width) > Style.imgMaxRatio && width > 100; @@ -85,6 +88,7 @@ class ImageGridView extends StatelessWidget { width: isLive ? item.width.toInt() : null, height: isLive ? item.height.toInt() : null, isLongPic: item.isLongPic, + size: item.size, ); }, ).toList(); @@ -153,7 +157,20 @@ class ImageGridView extends StatelessWidget { PopupMenuItem( height: 42, onTap: () => ImageUtils.downloadImg([item.url]), - child: const Text('保存图片', style: TextStyle(fontSize: 14)), + child: item.size == null + ? const Text('保存图片', style: TextStyle(fontSize: 14)) + : Text.rich( + TextSpan( + text: '保存图片', + children: [ + TextSpan( + text: '(${item.size!.formatSize})', + style: const TextStyle(fontSize: 12), + ), + ], + ), + style: const TextStyle(fontSize: 14), + ), ), if (PlatformUtils.isDesktop) PopupMenuItem( diff --git a/lib/common/widgets/image_viewer/gallery_viewer.dart b/lib/common/widgets/image_viewer/gallery_viewer.dart index 7f4dc17c2..2b43b5304 100644 --- a/lib/common/widgets/image_viewer/gallery_viewer.dart +++ b/lib/common/widgets/image_viewer/gallery_viewer.dart @@ -533,7 +533,20 @@ class _GalleryViewerState extends State ImageUtils.downloadImg([item.url]); }, dense: true, - title: const Text('保存图片', style: TextStyle(fontSize: 14)), + title: item.size == null + ? const Text('保存图片', style: TextStyle(fontSize: 14)) + : Text.rich( + TextSpan( + text: '保存图片', + children: [ + TextSpan( + text: '(${item.size!.formatSize})', + style: const TextStyle(fontSize: 12), + ), + ], + ), + style: const TextStyle(fontSize: 14), + ), ), if (PlatformUtils.isDesktop) ListTile( @@ -593,7 +606,20 @@ class _GalleryViewerState extends State PopupMenuItem( height: 42, onTap: () => ImageUtils.downloadImg([item.url]), - child: const Text('保存图片', style: TextStyle(fontSize: 14)), + child: item.size == null + ? const Text('保存图片', style: TextStyle(fontSize: 14)) + : Text.rich( + TextSpan( + text: '保存图片', + children: [ + TextSpan( + text: '(${item.size!.formatSize})', + style: const TextStyle(fontSize: 12), + ), + ], + ), + style: const TextStyle(fontSize: 14), + ), ), PopupMenuItem( height: 42, diff --git a/lib/grpc/bilibili/main/community/reply/v1.pb.dart b/lib/grpc/bilibili/main/community/reply/v1.pb.dart index 7c925e6e5..57fab89ea 100644 --- a/lib/grpc/bilibili/main/community/reply/v1.pb.dart +++ b/lib/grpc/bilibili/main/community/reply/v1.pb.dart @@ -2057,11 +2057,13 @@ class Picture extends $pb.GeneratedMessage { $core.String? imgSrc, $core.double? imgWidth, $core.double? imgHeight, + $core.double? imgSize, }) { final result = create(); if (imgSrc != null) result.imgSrc = imgSrc; if (imgWidth != null) result.imgWidth = imgWidth; if (imgHeight != null) result.imgHeight = imgHeight; + if (imgSize != null) result.imgSize = imgSize; return result; } @@ -2082,6 +2084,7 @@ class Picture extends $pb.GeneratedMessage { ..aOS(1, _omitFieldNames ? '' : 'imgSrc') ..aD(2, _omitFieldNames ? '' : 'imgWidth') ..aD(3, _omitFieldNames ? '' : 'imgHeight') + ..aD(4, _omitFieldNames ? '' : 'imgSize') ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -2128,6 +2131,15 @@ class Picture extends $pb.GeneratedMessage { $core.bool hasImgHeight() => $_has(2); @$pb.TagNumber(3) void clearImgHeight() => $_clearField(3); + + @$pb.TagNumber(4) + $core.double get imgSize => $_getN(3); + @$pb.TagNumber(4) + set imgSize($core.double value) => $_setDouble(3, value); + @$pb.TagNumber(4) + $core.bool hasImgSize() => $_has(3); + @$pb.TagNumber(4) + void clearImgSize() => $_clearField(4); } class ReplyCardLabel extends $pb.GeneratedMessage { diff --git a/lib/grpc/bilibili/main/community/reply/v1.pbjson.dart b/lib/grpc/bilibili/main/community/reply/v1.pbjson.dart index e23264ed5..403c8c55a 100644 --- a/lib/grpc/bilibili/main/community/reply/v1.pbjson.dart +++ b/lib/grpc/bilibili/main/community/reply/v1.pbjson.dart @@ -807,13 +807,15 @@ const Picture$json = { {'1': 'img_src', '3': 1, '4': 1, '5': 9, '10': 'imgSrc'}, {'1': 'img_width', '3': 2, '4': 1, '5': 1, '10': 'imgWidth'}, {'1': 'img_height', '3': 3, '4': 1, '5': 1, '10': 'imgHeight'}, + {'1': 'img_size', '3': 4, '4': 1, '5': 1, '10': 'imgSize'}, ], }; /// Descriptor for `Picture`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List pictureDescriptor = $convert.base64Decode( 'CgdQaWN0dXJlEhcKB2ltZ19zcmMYASABKAlSBmltZ1NyYxIbCglpbWdfd2lkdGgYAiABKAFSCG' - 'ltZ1dpZHRoEh0KCmltZ19oZWlnaHQYAyABKAFSCWltZ0hlaWdodA=='); + 'ltZ1dpZHRoEh0KCmltZ19oZWlnaHQYAyABKAFSCWltZ0hlaWdodBIZCghpbWdfc2l6ZRgEIAEo' + 'AVIHaW1nU2l6ZQ=='); @$core.Deprecated('Use replyCardLabelDescriptor instead') const ReplyCardLabel$json = { diff --git a/lib/models/common/image_preview_type.dart b/lib/models/common/image_preview_type.dart index e8dd206d3..d0649bed3 100644 --- a/lib/models/common/image_preview_type.dart +++ b/lib/models/common/image_preview_type.dart @@ -7,6 +7,7 @@ class SourceModel { final int? width; final int? height; final bool isLongPic; + final num? size; const SourceModel({ this.sourceType = SourceType.networkImage, @@ -15,5 +16,6 @@ class SourceModel { this.width, this.height, this.isLongPic = false, + this.size, }); } diff --git a/lib/models/dynamics/article_content_model.dart b/lib/models/dynamics/article_content_model.dart index 9911fe028..70510234d 100644 --- a/lib/models/dynamics/article_content_model.dart +++ b/lib/models/dynamics/article_content_model.dart @@ -44,7 +44,9 @@ class Pic { url = json['url']; width = (json['width'] as num?)?.toDouble(); height = (json['height'] as num?)?.toDouble(); - size = json['size']; + if (json['size'] case num size) { + this.size = size * 1024; + } pics = (json['pics'] as List?)?.map((item) => Pic.fromJson(item)).toList(); style = json['style']; liveUrl = json['live_url']; diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart index bfd750682..41435c580 100644 --- a/lib/models/dynamics/result.dart +++ b/lib/models/dynamics/result.dart @@ -1200,7 +1200,9 @@ class OpusPicModel extends PicModel { src = json['src']; url = json['url']; liveUrl = json['live_url']; - size = json['size']; + if (json['size'] case num size) { + this.size = size * 1024; + } } Map toJson() => { diff --git a/lib/pages/about/view.dart b/lib/pages/about/view.dart index dfe58c029..0c8a9b048 100644 --- a/lib/pages/about/view.dart +++ b/lib/pages/about/view.dart @@ -17,6 +17,7 @@ import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/cache_manager.dart'; import 'package:PiliPlus/utils/date_utils.dart'; import 'package:PiliPlus/utils/device_utils.dart'; +import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/login_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; @@ -58,7 +59,7 @@ class _AboutPageState extends State { void getCacheSize() { CacheManager.loadApplicationCache().then((res) { if (mounted) { - cacheSize.value = CacheManager.formatSize(res); + cacheSize.value = res.formatSize; } }); } diff --git a/lib/pages/article/controller.dart b/lib/pages/article/controller.dart index c434466bc..33b67c878 100644 --- a/lib/pages/article/controller.dart +++ b/lib/pages/article/controller.dart @@ -42,10 +42,11 @@ class ArticleController extends CommonDynController { opusData?.modules.moduleContent ?? articleData?.opus?.content; List? _images; - List images() => _images ??= opus! - .where((e) => e.paraType == 2 && e.pic != null) - .map((e) => SourceModel(url: e.pic!.pics!.first.url!)) - .toList(); + List images() => + _images ??= opus!.where((e) => e.paraType == 2 && e.pic != null).map((e) { + final pic = e.pic!.pics!.first; + return SourceModel(url: pic.url!, size: pic.size); + }).toList(); @override void onInit() { diff --git a/lib/pages/article/view.dart b/lib/pages/article/view.dart index 1961faf7a..4dab764db 100644 --- a/lib/pages/article/view.dart +++ b/lib/pages/article/view.dart @@ -289,7 +289,12 @@ class _ArticlePageState extends CommonDynPageState { onTap: () => PageUtils.imageView( quality: 60, imgList: pics - .map((e) => SourceModel(url: e.url!)) + .map( + (e) => SourceModel( + url: e.url!, + size: e.size, + ), + ) .toList(), initialPage: index, ), diff --git a/lib/pages/article/widgets/opus_content.dart b/lib/pages/article/widgets/opus_content.dart index f9f3129b2..b5d6762f5 100644 --- a/lib/pages/article/widgets/opus_content.dart +++ b/lib/pages/article/widgets/opus_content.dart @@ -258,6 +258,7 @@ class OpusContent extends StatelessWidget { width: e.width, height: e.height, url: e.url!, + size: e.size, ), ) .toList(), diff --git a/lib/pages/common/publish/common_rich_text_pub_page.dart b/lib/pages/common/publish/common_rich_text_pub_page.dart index d230bfff7..939452e08 100644 --- a/lib/pages/common/publish/common_rich_text_pub_page.dart +++ b/lib/pages/common/publish/common_rich_text_pub_page.dart @@ -122,6 +122,7 @@ abstract class CommonRichTextPubPageState OpusPicModel e => SourceModel( url: e.url!, sourceType: .networkImage, + size: e.size, ), }, ) diff --git a/lib/pages/download/detail/widgets/item.dart b/lib/pages/download/detail/widgets/item.dart index 593567aee..2137dd86f 100644 --- a/lib/pages/download/detail/widgets/item.dart +++ b/lib/pages/download/detail/widgets/item.dart @@ -14,8 +14,8 @@ import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart'; import 'package:PiliPlus/pages/common/multi_select/base.dart'; import 'package:PiliPlus/pages/download/downloading/view.dart'; import 'package:PiliPlus/services/download/download_service.dart'; -import 'package:PiliPlus/utils/cache_manager.dart'; import 'package:PiliPlus/utils/duration_utils.dart'; +import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/path_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; @@ -328,7 +328,7 @@ class DetailItem extends StatelessWidget { left: 0, bottom: 0, child: Text( - '${CacheManager.formatSize(entry.totalBytes)}${entry.ownerName != null ? ' ${entry.ownerName}' : ''}', + '${entry.totalBytes.formatSize}${entry.ownerName != null ? ' ${entry.ownerName}' : ''}', style: TextStyle( fontSize: 12, height: 1.6, @@ -365,7 +365,7 @@ class DetailItem extends StatelessWidget { DownloadStatus .downloading || status == DownloadStatus.pause - ? '${CacheManager.formatSize(curDownload.downloadedBytes)}/${CacheManager.formatSize(curDownload.totalBytes)}' + ? '${curDownload.downloadedBytes.formatSize}/${curDownload.totalBytes.formatSize}' : '', progress: curDownload.totalBytes == 0 ? 0 @@ -395,7 +395,7 @@ class DetailItem extends StatelessWidget { statusMsg: entry.status.message, progressStr: entry.totalBytes == 0 ? '' - : '${CacheManager.formatSize(entry.downloadedBytes)}/${CacheManager.formatSize(entry.totalBytes)}', + : '${entry.downloadedBytes.formatSize}/${entry.totalBytes.formatSize}', progress: entry.totalBytes == 0 ? 0 : entry.downloadedBytes / entry.totalBytes, diff --git a/lib/pages/download/view.dart b/lib/pages/download/view.dart index dc7a2d31c..f1d657edc 100644 --- a/lib/pages/download/view.dart +++ b/lib/pages/download/view.dart @@ -17,7 +17,7 @@ import 'package:PiliPlus/pages/download/detail/view.dart'; import 'package:PiliPlus/pages/download/detail/widgets/item.dart'; import 'package:PiliPlus/pages/download/search/view.dart'; import 'package:PiliPlus/services/download/download_service.dart'; -import 'package:PiliPlus/utils/cache_manager.dart'; +import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; @@ -373,7 +373,7 @@ class _DownloadPageState extends State with GridMixin { mainAxisAlignment: .spaceBetween, children: [ Text( - '${CacheManager.formatSize(pageInfo.entries.fold(0, (p, n) => p + n.totalBytes))} ${first.ownerName ?? ""}', + '${pageInfo.entries.fold(0, (p, n) => p + n.totalBytes).formatSize} ${first.ownerName ?? ""}', style: TextStyle( fontSize: 12, height: 1.6, diff --git a/lib/pages/dynamics/widgets/content_panel.dart b/lib/pages/dynamics/widgets/content_panel.dart index 2a7ea0547..3cfbee435 100644 --- a/lib/pages/dynamics/widgets/content_panel.dart +++ b/lib/pages/dynamics/widgets/content_panel.dart @@ -98,6 +98,7 @@ Widget content( height: item.height, url: item.url ?? '', liveUrl: item.liveUrl, + size: item.size, ), ) .toList(), diff --git a/lib/pages/dynamics/widgets/rich_node_panel.dart b/lib/pages/dynamics/widgets/rich_node_panel.dart index 347858743..3bc6d1f68 100644 --- a/lib/pages/dynamics/widgets/rich_node_panel.dart +++ b/lib/pages/dynamics/widgets/rich_node_panel.dart @@ -278,6 +278,7 @@ TextSpan? richNode( url: item.src ?? '', width: item.width, height: item.height, + size: item.size, ), ) .toList(), @@ -294,7 +295,9 @@ TextSpan? richNode( void onView(List list) { PageUtils.imageView( imgList: list - .map((e) => SourceModel(url: e.src!)) + .map( + (e) => SourceModel(url: e.src!, size: e.size), + ) .toList(), ); } diff --git a/lib/pages/setting/models/extra_settings.dart b/lib/pages/setting/models/extra_settings.dart index 1ded91806..d55561424 100644 --- a/lib/pages/setting/models/extra_settings.dart +++ b/lib/pages/setting/models/extra_settings.dart @@ -15,7 +15,7 @@ import 'package:PiliPlus/pages/setting/models/model.dart'; import 'package:PiliPlus/pages/setting/widgets/slider_dialog.dart'; import 'package:PiliPlus/services/download/download_service.dart'; import 'package:PiliPlus/utils/accounts.dart'; -import 'package:PiliPlus/utils/cache_manager.dart'; +import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/path_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; @@ -162,7 +162,7 @@ List get extraSettings => [ title: '最大缓存大小', getSubtitle: () { final num = Pref.maxCacheSize; - return '当前最大缓存大小: 「${num == 0 ? '无限' : CacheManager.formatSize(Pref.maxCacheSize)}」'; + return '当前最大缓存大小: 「${num == 0 ? '无限' : Pref.maxCacheSize.formatSize}」'; }, leading: const Icon(Icons.delete_outlined), onTap: _showCacheDialog, diff --git a/lib/pages/video/reply/widgets/reply_item_grpc.dart b/lib/pages/video/reply/widgets/reply_item_grpc.dart index f26ea6850..56bb5aef4 100644 --- a/lib/pages/video/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/reply/widgets/reply_item_grpc.dart @@ -334,6 +334,7 @@ class ReplyItemGrpc extends StatelessWidget { width: item.imgWidth, height: item.imgHeight, url: item.imgSrc, + size: item.imgSize * 1024, ), ) .toList(), diff --git a/lib/pages/webview/view.dart b/lib/pages/webview/view.dart index 281ba7eba..67698ae7c 100644 --- a/lib/pages/webview/view.dart +++ b/lib/pages/webview/view.dart @@ -6,7 +6,7 @@ import 'package:PiliPlus/http/browser_ua.dart'; import 'package:PiliPlus/main.dart'; import 'package:PiliPlus/models/common/webview_menu_type.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; -import 'package:PiliPlus/utils/cache_manager.dart'; +import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/login_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; @@ -267,9 +267,7 @@ class _WebViewPageState extends State { builder: (context) { String suggestedFilename = request.suggestedFilename .toString(); - String fileSize = CacheManager.formatSize( - request.contentLength.toDouble(), - ); + final fileSize = request.contentLength.formatSize; try { suggestedFilename = Uri.decodeComponent( suggestedFilename, diff --git a/lib/pages/whisper_detail/widget/chat_item.dart b/lib/pages/whisper_detail/widget/chat_item.dart index ece9ac258..0e2186c8f 100644 --- a/lib/pages/whisper_detail/widget/chat_item.dart +++ b/lib/pages/whisper_detail/widget/chat_item.dart @@ -624,6 +624,10 @@ class ChatItem extends StatelessWidget { final url = content['url']; final imgWidth = (content['width'] as num).toDouble(); final imgHeight = (content['height'] as num).toDouble(); + num? size; + if (content['size'] case num value) { + size = value * 1000; + } final width = math.min(220.0, imgWidth); final ratio = imgHeight / imgWidth; Widget child = NetworkImgLayer( @@ -638,7 +642,9 @@ class ChatItem extends StatelessWidget { ); } return GestureDetector( - onTap: () => PageUtils.imageView(imgList: [SourceModel(url: url)]), + onTap: () => PageUtils.imageView( + imgList: [SourceModel(url: url, size: size)], + ), child: child, ); } diff --git a/lib/utils/cache_manager.dart b/lib/utils/cache_manager.dart index faa527057..285676c69 100644 --- a/lib/utils/cache_manager.dart +++ b/lib/utils/cache_manager.dart @@ -44,18 +44,6 @@ abstract final class CacheManager { return total; } - // 缓存大小格式转换 - static String formatSize(num value) { - const unitArr = ['B', 'K', 'M', 'G', 'T', 'P']; - int index = 0; - while (value >= 1024) { - index++; - value = value / 1024; - } - String size = value.toStringAsFixed(2); - return size + (unitArr.elementAtOrNull(index) ?? ''); - } - // 清除 Library/Caches 目录及文件缓存 static Future clearLibraryCache() async { try { diff --git a/lib/utils/extension/num_ext.dart b/lib/utils/extension/num_ext.dart index a7b8e6cf8..fc2529814 100644 --- a/lib/utils/extension/num_ext.dart +++ b/lib/utils/extension/num_ext.dart @@ -1,5 +1,20 @@ import 'dart:math' show pow; +const unitArr = ['B', 'K', 'M', 'G', 'T', 'P']; + +extension NumExt on num { + String get formatSize { + var value = this; + int index = 0; + while (value >= 1024) { + index++; + value = value / 1024; + } + String size = value.toStringAsFixed(2); + return size + (unitArr.elementAtOrNull(index) ?? ''); + } +} + extension IntExt on int? { int? operator +(int other) => this == null ? null : this! + other; int? operator -(int other) => this == null ? null : this! - other;