From fc959ce3e521100f95239a28cd981455ebcfe397 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Thu, 3 Oct 2024 21:20:34 +0200 Subject: [PATCH] refactor: Use file selector on linux --- lib/pages/chat/chat.dart | 28 ++++----- lib/pages/chat_details/chat_details.dart | 16 +++--- .../homeserver_picker/homeserver_picker.dart | 11 ++-- lib/pages/new_group/new_group.dart | 11 ++-- lib/pages/new_space/new_space.dart | 13 ++--- lib/pages/settings/settings.dart | 14 ++--- .../settings_emotes/settings_emotes.dart | 34 ++++------- lib/pages/settings_style/settings_style.dart | 14 ++--- lib/utils/file_selector.dart | 57 +++++++++++++++++++ pubspec.lock | 32 +++++++++++ pubspec.yaml | 1 + scripts/enable-android-google-services.patch | 2 +- 12 files changed, 144 insertions(+), 89 deletions(-) create mode 100644 lib/utils/file_selector.dart diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index c47de7a83..4e45f01c7 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -10,7 +10,6 @@ import 'package:collection/collection.dart'; import 'package:desktop_drop/desktop_drop.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:go_router/go_router.dart'; @@ -29,11 +28,11 @@ import 'package:fluffychat/pages/chat/event_info_dialog.dart'; import 'package:fluffychat/pages/chat/recording_dialog.dart'; import 'package:fluffychat/pages/chat_details/chat_details.dart'; import 'package:fluffychat/utils/error_reporter.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; import '../../utils/account_bundles.dart'; import '../../utils/localized_exception_extension.dart'; @@ -481,17 +480,12 @@ class ChatController extends State } void sendFileAction() async { - final result = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles( - compressionQuality: 0, - allowMultiple: true, - ), - ); - if (result == null || result.files.isEmpty) return; + final files = await selectFiles(context, allowMultiple: true); + if (files.isEmpty) return; await showAdaptiveDialog( context: context, builder: (c) => SendFileDialog( - files: result.xFiles, + files: files, room: room, outerContext: context, ), @@ -511,19 +505,17 @@ class ChatController extends State } void sendImageAction() async { - final result = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles( - compressionQuality: 0, - type: FileType.image, - allowMultiple: true, - ), + final files = await selectFiles( + context, + allowMultiple: true, + extensions: imageExtensions, ); - if (result == null || result.files.isEmpty) return; + if (files.isEmpty) return; await showAdaptiveDialog( context: context, builder: (c) => SendFileDialog( - files: result.xFiles, + files: files, room: room, outerContext: context, ), diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 6c78adda6..3b1ea8da3 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:collection/collection.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:go_router/go_router.dart'; @@ -11,9 +10,9 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/pages/chat_details/chat_details_view.dart'; import 'package:fluffychat/pages/settings/settings.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; enum AliasActions { copy, delete, setCanonical } @@ -165,16 +164,15 @@ class ChatDetailsController extends State { name: result.path, ); } else { - final picked = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles( - type: FileType.image, - withData: true, - ), + final picked = await selectFiles( + context, + allowMultiple: false, + extensions: imageExtensions, ); - final pickedFile = picked?.files.firstOrNull; + final pickedFile = picked.firstOrNull; if (pickedFile == null) return; file = MatrixFile( - bytes: pickedFile.bytes!, + bytes: await pickedFile.readAsBytes(), name: pickedFile.name, ); } diff --git a/lib/pages/homeserver_picker/homeserver_picker.dart b/lib/pages/homeserver_picker/homeserver_picker.dart index 955aa3c56..d5fe0700a 100644 --- a/lib/pages/homeserver_picker/homeserver_picker.dart +++ b/lib/pages/homeserver_picker/homeserver_picker.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:collection/collection.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_web_auth_2/flutter_web_auth_2.dart'; import 'package:go_router/go_router.dart'; @@ -15,8 +14,8 @@ import 'package:universal_html/html.dart' as html; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/homeserver_picker/homeserver_picker_view.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; import '../../utils/localized_exception_extension.dart'; @@ -201,10 +200,8 @@ class HomeserverPickerController extends State { Widget build(BuildContext context) => HomeserverPickerView(this); Future restoreBackup() async { - final picked = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles(withData: true), - ); - final file = picked?.files.firstOrNull; + final picked = await selectFiles(context); + final file = picked.firstOrNull; if (file == null) return; setState(() { error = null; @@ -212,7 +209,7 @@ class HomeserverPickerController extends State { }); try { final client = Matrix.of(context).getLoginClient(); - await client.importDump(String.fromCharCodes(file.bytes!)); + await client.importDump(String.fromCharCodes(await file.readAsBytes())); Matrix.of(context).initMatrix(); } catch (e) { setState(() { diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 107d3661b..393e88372 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -2,11 +2,11 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart' as sdk; import 'package:fluffychat/pages/new_group/new_group_view.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/widgets/matrix.dart'; class NewGroup extends StatefulWidget { @@ -35,15 +35,16 @@ class NewGroupController extends State { void setGroupCanBeFound(bool b) => setState(() => groupCanBeFound = b); void selectPhoto() async { - final photo = await FilePicker.platform.pickFiles( - type: FileType.image, + final photo = await selectFiles( + context, + extensions: imageExtensions, allowMultiple: false, - withData: true, ); + final bytes = await photo.singleOrNull?.readAsBytes(); setState(() { avatarUrl = null; - avatar = photo?.files.singleOrNull?.bytes; + avatar = bytes; }); } diff --git a/lib/pages/new_space/new_space.dart b/lib/pages/new_space/new_space.dart index a5a55c8b1..0190f15ce 100644 --- a/lib/pages/new_space/new_space.dart +++ b/lib/pages/new_space/new_space.dart @@ -2,13 +2,13 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart' as sdk; import 'package:matrix/matrix.dart'; import 'package:fluffychat/pages/new_space/new_space_view.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -32,15 +32,14 @@ class NewSpaceController extends State { Uri? avatarUrl; void selectPhoto() async { - final photo = await FilePicker.platform.pickFiles( - type: FileType.image, - allowMultiple: false, - withData: true, + final photo = await selectFiles( + context, + extensions: imageExtensions, ); - + final bytes = await photo.firstOrNull?.readAsBytes(); setState(() { avatarUrl = null; - avatar = photo?.files.singleOrNull?.bytes; + avatar = bytes; }); } diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index d844063b1..455de997b 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -4,14 +4,13 @@ import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:collection/collection.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:image_picker/image_picker.dart'; import 'package:matrix/matrix.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/widgets/app_lock.dart'; import '../../widgets/matrix.dart'; import '../bootstrap/bootstrap_dialog.dart'; import 'settings_view.dart'; @@ -136,16 +135,11 @@ class SettingsController extends State { name: result.path, ); } else { - final result = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles( - type: FileType.image, - withData: true, - ), - ); - final pickedFile = result?.files.firstOrNull; + final result = await selectFiles(context, extensions: imageExtensions); + final pickedFile = result.firstOrNull; if (pickedFile == null) return; file = MatrixFile( - bytes: pickedFile.bytes!, + bytes: await pickedFile.readAsBytes(), name: pickedFile.name, ); } diff --git a/lib/pages/settings_emotes/settings_emotes.dart b/lib/pages/settings_emotes/settings_emotes.dart index fbef5479c..8a8eca430 100644 --- a/lib/pages/settings_emotes/settings_emotes.dart +++ b/lib/pages/settings_emotes/settings_emotes.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:collection/collection.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:go_router/go_router.dart'; @@ -13,8 +12,8 @@ import 'package:http/http.dart' hide Client; import 'package:matrix/matrix.dart'; import 'package:fluffychat/utils/client_manager.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart'; -import 'package:fluffychat/widgets/app_lock.dart'; import '../../widgets/matrix.dart'; import 'import_archive_dialog.dart'; import 'settings_emotes_view.dart'; @@ -222,16 +221,11 @@ class EmotesSettingsController extends State { void imagePickerAction( ValueNotifier controller, ) async { - final result = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles( - type: FileType.image, - withData: true, - ), - ); - final pickedFile = result?.files.firstOrNull; + final result = await selectFiles(context, extensions: imageExtensions); + final pickedFile = result.firstOrNull; if (pickedFile == null) return; var file = MatrixImageFile( - bytes: pickedFile.bytes!, + bytes: await pickedFile.readAsBytes(), name: pickedFile.name, ); try { @@ -282,21 +276,17 @@ class EmotesSettingsController extends State { final result = await showFutureLoadingDialog( context: context, future: () async { - final result = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: [ - 'zip', - // TODO: add further encoders - ], - // TODO: migrate to stream, currently brrrr because of `archive_io`. - withData: true, - ), + final result = await selectFiles( + context, + extensions: [ + 'zip', + // TODO: add further encoders + ], ); - if (result == null) return null; + if (result.isEmpty) return null; - final buffer = InputStream(result.files.single.bytes); + final buffer = InputStream(await result.first.readAsBytes()); final archive = ZipDecoder().decodeBuffer(buffer); diff --git a/lib/pages/settings_style/settings_style.dart b/lib/pages/settings_style/settings_style.dart index 58f8e2c1b..62ba84bf1 100644 --- a/lib/pages/settings_style/settings_style.dart +++ b/lib/pages/settings_style/settings_style.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/utils/account_config.dart'; -import 'package:fluffychat/widgets/app_lock.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/widgets/theme_builder.dart'; import '../../widgets/matrix.dart'; import 'settings_style_view.dart'; @@ -26,20 +25,15 @@ class SettingsStyleController extends State { void setWallpaper() async { final client = Matrix.of(context).client; - final picked = await AppLock.of(context).pauseWhile( - FilePicker.platform.pickFiles( - type: FileType.image, - withData: true, - ), - ); - final pickedFile = picked?.files.firstOrNull; + final picked = await selectFiles(context, extensions: imageExtensions); + final pickedFile = picked.firstOrNull; if (pickedFile == null) return; await showFutureLoadingDialog( context: context, future: () async { final url = await client.uploadContent( - pickedFile.bytes!, + await pickedFile.readAsBytes(), filename: pickedFile.name, ); await client.updateApplicationAccountConfig( diff --git a/lib/utils/file_selector.dart b/lib/utils/file_selector.dart new file mode 100644 index 000000000..3bdcd82f9 --- /dev/null +++ b/lib/utils/file_selector.dart @@ -0,0 +1,57 @@ +import 'package:flutter/widgets.dart'; + +import 'package:file_picker/file_picker.dart'; +import 'package:file_selector/file_selector.dart'; + +import 'package:fluffychat/utils/platform_infos.dart'; +import 'package:fluffychat/widgets/app_lock.dart'; + +Future> selectFiles( + BuildContext context, { + String? title, + List? extensions, + bool allowMultiple = false, +}) async { + if (!PlatformInfos.isLinux) { + final result = await AppLock.of(context).pauseWhile( + FilePicker.platform.pickFiles( + compressionQuality: 0, + allowMultiple: allowMultiple, + allowedExtensions: extensions, + ), + ); + return result?.xFiles ?? []; + } + + if (allowMultiple) { + return await AppLock.of(context).pauseWhile( + openFiles( + confirmButtonText: title, + acceptedTypeGroups: [ + if (extensions != null) XTypeGroup(extensions: extensions), + ], + ), + ); + } + final file = await AppLock.of(context).pauseWhile( + openFile( + confirmButtonText: title, + acceptedTypeGroups: [ + if (extensions != null) XTypeGroup(extensions: extensions), + ], + ), + ); + if (file == null) return []; + return [file]; +} + +const imageExtensions = [ + 'png', + 'PNG', + 'jpg', + 'JPG', + 'jpeg', + 'JPEG', + 'webp', + 'WebP', +]; diff --git a/pubspec.lock b/pubspec.lock index af057910e..81920a2ed 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -382,6 +382,30 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.2" + file_selector: + dependency: "direct main" + description: + name: file_selector + sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + file_selector_android: + dependency: transitive + description: + name: file_selector_android + sha256: b8c9717a0177ca6fa035554b82cd6c83b838ddc66b7704eb6df0f77f027ecc90 + url: "https://pub.dev" + source: hosted + version: "0.5.1+7" + file_selector_ios: + dependency: transitive + description: + name: file_selector_ios + sha256: "38ebf91ecbcfa89a9639a0854ccaed8ab370c75678938eebca7d34184296f0bb" + url: "https://pub.dev" + source: hosted + version: "0.5.3" file_selector_linux: dependency: transitive description: @@ -406,6 +430,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.2" + file_selector_web: + dependency: transitive + description: + name: file_selector_web + sha256: c4c0ea4224d97a60a7067eca0c8fd419e708ff830e0c83b11a48faf566cec3e7 + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" file_selector_windows: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f555d4a3e..90730e4ae 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,7 @@ dependencies: emojis: ^0.9.9 #fcm_shared_isolate: ^0.1.0 file_picker: ^8.1.2 + file_selector: ^1.0.3 flutter: sdk: flutter flutter_app_badger: ^1.5.0 diff --git a/scripts/enable-android-google-services.patch b/scripts/enable-android-google-services.patch index ec7139117..aca4f69b8 100644 --- a/scripts/enable-android-google-services.patch +++ b/scripts/enable-android-google-services.patch @@ -132,5 +132,5 @@ index 69c80d6e..efd32d89 100644 - #fcm_shared_isolate: ^0.1.0 + fcm_shared_isolate: ^0.1.0 file_picker: ^8.1.2 + file_selector: ^1.0.3 flutter: - sdk: flutter