From 0e1874b2269511dcb58726f0d440efe32aade573 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Sat, 19 Jul 2025 10:23:33 +0200 Subject: [PATCH 1/3] refactor: Better UX for accepting declining invite --- lib/l10n/intl_en.arb | 3 +- lib/pages/chat_list/chat_list.dart | 109 +++++++----------------- lib/pages/chat_list/chat_list_item.dart | 57 ++++++------- 3 files changed, 57 insertions(+), 112 deletions(-) diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 97fdc78ef..6666ad317 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -3241,5 +3241,6 @@ "commandHint_logoutall": "Logout all active devices", "displayNavigationRail": "Show navigation rail on mobile", "customReaction": "Custom reaction", - "moreEvents": "More events" + "moreEvents": "More events", + "declineInvitation": "Decline invitation" } diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 1b07b0758..7d64f13d1 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -20,7 +20,6 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/show_scaffold_dialog.dart'; import 'package:fluffychat/utils/show_update_snackbar.dart'; -import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart'; @@ -114,82 +113,6 @@ class ChatListController extends State void onChatTap(Room room) async { if (room.membership == Membership.invite) { - final theme = Theme.of(context); - final inviteEvent = room.getState( - EventTypes.RoomMember, - room.client.userID!, - ); - final matrixLocals = MatrixLocals(L10n.of(context)); - final action = await showAdaptiveDialog( - context: context, - builder: (context) => AlertDialog.adaptive( - title: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256), - child: Center( - child: Text( - room.getLocalizedDisplayname(matrixLocals), - textAlign: TextAlign.center, - ), - ), - ), - content: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), - child: Text( - inviteEvent == null - ? L10n.of(context).inviteForMe - : inviteEvent.content.tryGet('reason') ?? - L10n.of(context).youInvitedBy( - room - .unsafeGetUserFromMemoryOrFallback( - inviteEvent.senderId, - ) - .calcDisplayname(i18n: matrixLocals), - ), - textAlign: TextAlign.center, - ), - ), - actions: [ - AdaptiveDialogAction( - onPressed: () => Navigator.of(context).pop(InviteAction.accept), - bigButtons: true, - child: Text(L10n.of(context).accept), - ), - AdaptiveDialogAction( - onPressed: () => Navigator.of(context).pop(InviteAction.decline), - bigButtons: true, - child: Text( - L10n.of(context).decline, - style: TextStyle(color: theme.colorScheme.error), - ), - ), - AdaptiveDialogAction( - onPressed: () => Navigator.of(context).pop(InviteAction.block), - bigButtons: true, - child: Text( - L10n.of(context).block, - style: TextStyle(color: theme.colorScheme.error), - ), - ), - ], - ), - ); - switch (action) { - case null: - return; - case InviteAction.accept: - break; - case InviteAction.decline: - await showFutureLoadingDialog( - context: context, - future: () => room.leave(), - ); - return; - case InviteAction.block: - final userId = inviteEvent?.senderId; - context.go('/rooms/settings/security/ignorelist', extra: userId); - return; - } - if (!mounted) return; final joinResult = await showFutureLoadingDialog( context: context, future: () async { @@ -680,6 +603,26 @@ class ChatListController extends State ], ), ), + if (room.membership == Membership.invite) + PopupMenuItem( + value: ChatContextAction.block, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.block_outlined, + color: Theme.of(context).colorScheme.onErrorContainer, + ), + const SizedBox(width: 12), + Text( + L10n.of(context).block, + style: TextStyle( + color: Theme.of(context).colorScheme.onErrorContainer, + ), + ), + ], + ), + ), ], ); @@ -715,6 +658,15 @@ class ChatListController extends State ), ); return; + case ChatContextAction.block: + final inviteEvent = room.getState( + EventTypes.RoomMember, + room.client.userID!, + ); + context.go( + '/rooms/settings/security/ignorelist', + extra: inviteEvent?.senderId, + ); case ChatContextAction.leave: final confirmed = await showOkCancelAlertDialog( context: context, @@ -981,6 +933,5 @@ enum ChatContextAction { mute, leave, addToSpace, + block, } - -enum InviteAction { accept, decline, block } diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index 6ee2ee941..639ccd5b4 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -35,32 +35,6 @@ class ChatListItem extends StatelessWidget { super.key, }); - Future archiveAction(BuildContext context) async { - { - if ([Membership.leave, Membership.ban].contains(room.membership)) { - final forgetResult = await showFutureLoadingDialog( - context: context, - future: () => room.forget(), - ); - return forgetResult.isValue; - } - final confirmed = await showOkCancelAlertDialog( - context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).leave, - cancelLabel: L10n.of(context).cancel, - message: L10n.of(context).archiveRoomDescription, - isDestructive: true, - ); - if (confirmed != OkCancelResult.ok) return false; - final leaveResult = await showFutureLoadingDialog( - context: context, - future: () => room.leave(), - ); - return leaveResult.isValue; - } - } - @override Widget build(BuildContext context) { final theme = Theme.of(context); @@ -69,7 +43,7 @@ class ChatListItem extends StatelessWidget { final typingText = room.getLocalizedTypingText(context); final lastEvent = room.lastEvent; final ownMessage = lastEvent?.senderId == room.client.userID; - final unread = room.isUnread || room.membership == Membership.invite; + final unread = room.isUnread; final directChatMatrixId = room.directChatMatrixID; final isDirectChat = directChatMatrixId != null; final unreadBubbleSize = unread || room.hasNewMessages @@ -357,8 +331,7 @@ class ChatListItem extends StatelessWidget { room.notificationCount.toString().length + 9, decoration: BoxDecoration( - color: room.highlightCount > 0 || - room.membership == Membership.invite + color: room.highlightCount > 0 ? theme.colorScheme.error : hasNotifications || room.markedUnread ? theme.colorScheme.primary @@ -369,8 +342,7 @@ class ChatListItem extends StatelessWidget { ? Text( room.notificationCount.toString(), style: TextStyle( - color: room.highlightCount > 0 || - room.membership == Membership.invite + color: room.highlightCount > 0 ? theme.colorScheme.onError : hasNotifications ? theme.colorScheme.onPrimary @@ -386,7 +358,28 @@ class ChatListItem extends StatelessWidget { ), onTap: onTap, trailing: onForget == null - ? null + ? room.membership == Membership.invite + ? IconButton( + tooltip: L10n.of(context).declineInvitation, + icon: const Icon(Icons.delete_forever_outlined), + color: theme.colorScheme.error, + onPressed: () async { + final consent = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).declineInvitation, + message: L10n.of(context).areYouSure, + okLabel: L10n.of(context).yes, + isDestructive: true, + ); + if (consent != OkCancelResult.ok) return; + if (!context.mounted) return; + await showFutureLoadingDialog( + context: context, + future: room.leave, + ); + }, + ) + : null : IconButton( icon: const Icon(Icons.delete_outlined), onPressed: onForget, From 933119a3085edecfe6131c182bc44ddd107061d1 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Sat, 19 Jul 2025 10:33:03 +0200 Subject: [PATCH 2/3] refactor: Remove unused dependencies --- integration_test/app_test.dart | 5 -- .../homeserver_picker/homeserver_picker.dart | 12 ---- lib/utils/client_manager.dart | 7 -- linux/flutter/generated_plugin_registrant.cc | 4 -- linux/flutter/generated_plugins.cmake | 1 - macos/Flutter/GeneratedPluginRegistrant.swift | 4 -- pubspec.lock | 64 ------------------- pubspec.yaml | 4 -- .../flutter/generated_plugin_registrant.cc | 3 - windows/flutter/generated_plugins.cmake | 1 - 10 files changed, 105 deletions(-) diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart index 90f423077..4b49aac6b 100644 --- a/integration_test/app_test.dart +++ b/integration_test/app_test.dart @@ -6,7 +6,6 @@ import 'package:fluffychat/pages/invitation_selection/invitation_selection_view. import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:hive_flutter/hive_flutter.dart'; import 'package:integration_test/integration_test.dart'; import 'package:fluffychat/main.dart' as app; @@ -28,10 +27,6 @@ void main() { SharedPreferences.setMockInitialValues({ SettingKeys.showNoGoogle: false, }); - try { - Hive.deleteFromDisk(); - Hive.initFlutter(); - } catch (_) {} }, ); diff --git a/lib/pages/homeserver_picker/homeserver_picker.dart b/lib/pages/homeserver_picker/homeserver_picker.dart index 01d3c2184..b17a3bc06 100644 --- a/lib/pages/homeserver_picker/homeserver_picker.dart +++ b/lib/pages/homeserver_picker/homeserver_picker.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; import 'package:flutter_web_auth_2/flutter_web_auth_2.dart'; import 'package:go_router/go_router.dart'; -import 'package:hive_flutter/hive_flutter.dart'; import 'package:matrix/matrix.dart'; import 'package:universal_html/html.dart' as html; import 'package:url_launcher/url_launcher_string.dart'; @@ -45,17 +44,6 @@ class HomeserverPickerController extends State { Future _checkTorBrowser() async { if (!kIsWeb) return; - Hive.openBox('test').then((value) => null).catchError( - (e, s) async { - await showOkAlertDialog( - context: context, - title: L10n.of(context).indexedDbErrorTitle, - message: L10n.of(context).indexedDbErrorLong, - ); - _checkTorBrowser(); - }, - ); - final isTor = await TorBrowserDetector.isTorBrowser; isTorBrowser = isTor; } diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 25b5af34e..ddda56824 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -6,10 +6,8 @@ import 'package:collection/collection.dart'; import 'package:desktop_notifications/desktop_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod; -import 'package:hive_flutter/hive_flutter.dart'; import 'package:matrix/encryption/utils/key_verification.dart'; import 'package:matrix/matrix.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:universal_html/html.dart' as html; @@ -29,11 +27,6 @@ abstract class ClientManager { bool initialize = true, required SharedPreferences store, }) async { - if (PlatformInfos.isLinux) { - Hive.init((await getApplicationSupportDirectory()).path); - } else { - await Hive.initFlutter(); - } final clientNames = {}; try { final clientNamesList = store.getStringList(clientNamespace) ?? []; diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 016e81fd9..f6178cd62 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -45,9 +44,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) handy_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "HandyWindowPlugin"); handy_window_plugin_register_with_registrar(handy_window_registrar); - g_autoptr(FlPluginRegistrar) pasteboard_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); - pasteboard_plugin_register_with_registrar(pasteboard_registrar); g_autoptr(FlPluginRegistrar) record_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); record_linux_plugin_register_with_registrar(record_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index a16d09682..9d145db6f 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -11,7 +11,6 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_webrtc gtk handy_window - pasteboard record_linux sqlcipher_flutter_libs url_launcher_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 016f51cf6..dd7fa9ed5 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -21,12 +21,10 @@ import flutter_webrtc import geolocator_apple import just_audio import package_info_plus -import pasteboard import path_provider_foundation import record_macos import share_plus import shared_preferences_foundation -import sqflite_darwin import sqlcipher_flutter_libs import url_launcher_macos import video_compress @@ -51,12 +49,10 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) - PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) - SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin")) diff --git a/pubspec.lock b/pubspec.lock index ebdd77dac..8d1f6b7de 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -475,14 +475,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_cache_manager: - dependency: "direct main" - description: - name: flutter_cache_manager - sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" - url: "https://pub.dev" - source: hosted - version: "3.4.1" flutter_driver: dependency: transitive description: flutter @@ -871,22 +863,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.1" - hive: - dependency: "direct main" - description: - name: hive - sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - hive_flutter: - dependency: "direct main" - description: - name: hive_flutter - sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc - url: "https://pub.dev" - source: hosted - version: "1.1.0" html: dependency: "direct main" description: @@ -1284,14 +1260,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.21.45" - pasteboard: - dependency: "direct main" - description: - name: pasteboard - sha256: "1c8b6a8b3f1d12e55d4e9404433cda1b4abe66db6b17bc2d2fb5965772c04674" - url: "https://pub.dev" - source: hosted - version: "0.2.0" path: dependency: "direct main" description: @@ -1817,22 +1785,6 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_android: - dependency: transitive - description: - name: sqflite_android - sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b" - url: "https://pub.dev" - source: hosted - version: "2.4.1" sqflite_common: dependency: transitive description: @@ -1849,22 +1801,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.5" - sqflite_darwin: - dependency: transitive - description: - name: sqflite_darwin - sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_platform_interface: - dependency: transitive - description: - name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.dev" - source: hosted - version: "2.4.0" sqlcipher_flutter_libs: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1b90ee76d..8438c4669 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,6 @@ dependencies: file_selector: ^1.0.3 flutter: sdk: flutter - flutter_cache_manager: ^3.4.1 flutter_foreground_task: ^6.1.3 flutter_highlighter: ^0.1.1 flutter_linkify: ^6.0.0 @@ -50,8 +49,6 @@ dependencies: geolocator: ^13.0.1 go_router: ^15.1.2 handy_window: ^0.4.0 - hive: ^2.2.3 - hive_flutter: ^1.1.0 html: ^0.15.4 http: ^1.2.0 image: ^4.1.7 @@ -65,7 +62,6 @@ dependencies: native_imaging: ^0.2.0 opus_caf_converter_dart: ^1.0.1 package_info_plus: ^8.0.2 - pasteboard: ^0.2.0 path: ^1.9.0 path_provider: ^2.1.2 permission_handler: ^11.0.1 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 7ab3698dc..d083bd166 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -39,8 +38,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FlutterWebRTCPlugin")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); - PasteboardPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("PasteboardPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); RecordWindowsPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 7e3e64db1..3276ee890 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -11,7 +11,6 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_secure_storage_windows flutter_webrtc geolocator_windows - pasteboard permission_handler_windows record_windows share_plus From 458dfa6e3e93912c78c49eb5d9247bccb42f3296 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Sat, 19 Jul 2025 10:54:03 +0200 Subject: [PATCH 3/3] build: Fetch version correctly for snap --- snap/snapcraft.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 779770c98..dd8d407a8 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,7 +1,7 @@ name: fluffychat title: FluffyChat base: core24 -version: 1.27.0 +adopt-info: fluffychat license: AGPL-3.0 summary: The cutest messenger in the Matrix network description: | @@ -82,6 +82,8 @@ parts: # Workaround for Flutter build error: rm -rf build + craftctl set version="$(yq e '.version' pubspec.yaml | sed 's/\(.*\)+.*/\1/')" + flutter build linux --release -v mkdir -p $CRAFT_PART_INSTALL/bin/ cp -r build/linux/*/release/bundle/* $CRAFT_PART_INSTALL/bin/ @@ -93,6 +95,7 @@ parts: - libpciaccess-dev build-snaps: - rustup + - yq stage-packages: - libsecret-1-0 - libjsoncpp25