diff --git a/lib/utils/format.dart b/lib/utils/format.dart new file mode 100644 index 00000000..9e376f35 --- /dev/null +++ b/lib/utils/format.dart @@ -0,0 +1,9 @@ +String formatFileSize(int bytes) { + if (bytes <= 0) return '0 B'; + if (bytes < 1024) return '$bytes B'; + if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB'; + if (bytes < 1024 * 1024 * 1024) { + return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB'; + } + return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB'; +} diff --git a/lib/widgets/content/attachment_preview.dart b/lib/widgets/content/attachment_preview.dart index 17d6dedf..da611a47 100644 --- a/lib/widgets/content/attachment_preview.dart +++ b/lib/widgets/content/attachment_preview.dart @@ -10,6 +10,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/file.dart'; import 'package:island/pods/network.dart'; import 'package:island/services/file.dart'; +import 'package:island/utils/format.dart'; import 'package:island/widgets/alert.dart'; import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/sheet.dart'; @@ -284,6 +285,13 @@ class AttachmentPreview extends HookConsumerWidget { Builder( key: ValueKey(item.hashCode), builder: (context) { + final fallbackIcon = switch (item.type) { + UniversalFileType.video => Symbols.video_file, + UniversalFileType.audio => Symbols.audio_file, + UniversalFileType.image => Symbols.image, + _ => Symbols.insert_drive_file, + }; + if (item.isOnCloud) { return CloudFileWidget(item: item.data); } else if (item.data is XFile) { @@ -309,9 +317,23 @@ class AttachmentPreview extends HookConsumerWidget { : Image.file(File(file.path)); default: return Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Symbols.document_scanner), + Icon(fallbackIcon), + const Gap(6), Text(file.name), + FutureBuilder( + future: file.length(), + builder: (context, snapshot) { + if (snapshot.hasData) { + final size = snapshot.data as int; + return Text( + formatFileSize(size), + ).fontSize(11); + } + return const SizedBox.shrink(); + }, + ), ], ); } @@ -321,7 +343,14 @@ class AttachmentPreview extends HookConsumerWidget { return Image.memory(item.data); default: return Column( - children: [const Icon(Symbols.document_scanner)], + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(fallbackIcon), + const Gap(6), + Text( + formatFileSize(item.data.length), + ).fontSize(11), + ], ); } } diff --git a/lib/widgets/content/cloud_file_collection.dart b/lib/widgets/content/cloud_file_collection.dart index 8b960ab5..ca308c8b 100644 --- a/lib/widgets/content/cloud_file_collection.dart +++ b/lib/widgets/content/cloud_file_collection.dart @@ -17,6 +17,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/file.dart'; import 'package:island/pods/config.dart'; import 'package:island/pods/network.dart'; +import 'package:island/utils/format.dart'; import 'package:island/widgets/alert.dart'; import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/sensitive.dart'; @@ -359,16 +360,6 @@ class CloudFileZoomIn extends HookConsumerWidget { } } - String formatFileSize(int bytes) { - if (bytes <= 0) return '0 B'; - if (bytes < 1024) return '$bytes B'; - if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB'; - if (bytes < 1024 * 1024 * 1024) { - return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB'; - } - return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB'; - } - void showInfoSheet() { final theme = Theme.of(context); final exifData = item.fileMeta?['exif'] as Map? ?? {}; diff --git a/lib/widgets/content/cloud_files.dart b/lib/widgets/content/cloud_files.dart index 6717e2ba..c9d1bfe4 100644 --- a/lib/widgets/content/cloud_files.dart +++ b/lib/widgets/content/cloud_files.dart @@ -9,6 +9,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/file.dart'; import 'package:island/pods/config.dart'; import 'package:island/services/time.dart'; +import 'package:island/utils/format.dart'; import 'package:island/widgets/content/audio.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -35,16 +36,6 @@ class CloudFileWidget extends HookConsumerWidget { final serverUrl = ref.watch(serverUrlProvider); final uri = '$serverUrl/drive/files/${item.id}'; - String formatFileSize(int bytes) { - if (bytes <= 0) return '0 B'; - if (bytes < 1024) return '$bytes B'; - if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB'; - if (bytes < 1024 * 1024 * 1024) { - return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB'; - } - return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB'; - } - var ratio = item.fileMeta?['ratio'] is num ? item.fileMeta!['ratio'].toDouble()