From 4607b773552fd76cd7e9af4d18ae9ea7c79b15d0 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 15 Nov 2025 13:36:00 +0800 Subject: [PATCH] :recycle: Better file icons --- lib/utils/file_icon_utils.dart | 61 +++++++++++++++++++++++++++++++++ lib/widgets/file_list_view.dart | 44 ++---------------------- 2 files changed, 64 insertions(+), 41 deletions(-) create mode 100644 lib/utils/file_icon_utils.dart diff --git a/lib/utils/file_icon_utils.dart b/lib/utils/file_icon_utils.dart new file mode 100644 index 00000000..e6b19963 --- /dev/null +++ b/lib/utils/file_icon_utils.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import 'package:styled_widget/styled_widget.dart'; + +import '../models/file.dart'; +import '../widgets/content/cloud_files.dart'; + +/// Returns an appropriate icon widget for the given file based on its MIME type +Widget getFileIcon(SnCloudFile file, {required double size}) { + final itemType = file.mimeType?.split('/').firstOrNull; + final mimeType = file.mimeType ?? ''; + final extension = file.name.split('.').lastOrNull?.toLowerCase() ?? ''; + + // For images, show the actual image thumbnail + if (itemType == 'image') { + return CloudImageWidget(file: file); + } + + // Return icon based on MIME type or file extension + final icon = switch ((itemType, mimeType, extension)) { + ('audio', _, _) => Symbols.audio_file, + ('video', _, _) => Symbols.video_file, + ('application', 'application/pdf', _) => Symbols.picture_as_pdf, + ('application', 'application/zip', _) => Symbols.archive, + ('application', 'application/x-rar-compressed', _) => Symbols.archive, + ( + 'application', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + _, + ) || + ('application', 'application/msword', _) => Symbols.description, + ( + 'application', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + _, + ) || + ('application', 'application/vnd.ms-excel', _) => Symbols.table_chart, + ( + 'application', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + _, + ) || + ('application', 'application/vnd.ms-powerpoint', _) => Symbols.slideshow, + ('text', _, _) => Symbols.article, + ('application', _, 'js') || + ('application', _, 'dart') || + ('application', _, 'py') || + ('application', _, 'java') || + ('application', _, 'cpp') || + ('application', _, 'c') || + ('application', _, 'cs') => Symbols.code, + ('application', _, 'json') || + ('application', _, 'xml') => Symbols.data_object, + (_, _, 'md') => Symbols.article, + (_, _, 'html') => Symbols.web, + (_, _, 'css') => Symbols.css, + _ => Symbols.description, // Default icon + }; + + return Icon(icon, size: size, fill: 1).center(); +} diff --git a/lib/widgets/file_list_view.dart b/lib/widgets/file_list_view.dart index acbf53b3..96b0c7e3 100644 --- a/lib/widgets/file_list_view.dart +++ b/lib/widgets/file_list_view.dart @@ -10,9 +10,9 @@ import 'package:island/models/file.dart'; import 'package:island/pods/file_list.dart'; import 'package:island/pods/network.dart'; import 'package:island/services/file_uploader.dart'; +import 'package:island/utils/file_icon_utils.dart'; import 'package:island/utils/format.dart'; import 'package:island/widgets/alert.dart'; -import 'package:island/widgets/content/cloud_files.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -81,8 +81,6 @@ class FileListView extends HookConsumerWidget { }, unindexedFile: (unindexedFileItem) { final file = unindexedFileItem.file; - final itemType = - file.mimeType?.split('/').firstOrNull; return ListTile( leading: ClipRRect( borderRadius: const BorderRadius.all( @@ -91,24 +89,7 @@ class FileListView extends HookConsumerWidget { child: SizedBox( height: 48, width: 48, - child: switch (itemType) { - 'image' => CloudImageWidget(file: file), - 'audio' => - const Icon( - Symbols.audio_file, - fill: 1, - ).center(), - 'video' => - const Icon( - Symbols.video_file, - fill: 1, - ).center(), - _ => - const Icon( - Symbols.body_system, - fill: 1, - ).center(), - }, + child: getFileIcon(file, size: 24), ), ), title: @@ -179,8 +160,6 @@ class FileListView extends HookConsumerWidget { return item.map( file: (fileItem) { final file = fileItem.fileIndex.file; - final itemType = - file.mimeType?.split('/').firstOrNull; return ListTile( leading: ClipRRect( borderRadius: const BorderRadius.all( @@ -189,24 +168,7 @@ class FileListView extends HookConsumerWidget { child: SizedBox( height: 48, width: 48, - child: switch (itemType) { - 'image' => CloudImageWidget(file: file), - 'audio' => - const Icon( - Symbols.audio_file, - fill: 1, - ).center(), - 'video' => - const Icon( - Symbols.video_file, - fill: 1, - ).center(), - _ => - const Icon( - Symbols.body_system, - fill: 1, - ).center(), - }, + child: getFileIcon(file, size: 24), ), ), title: