diff --git a/.github/workflows/matrix_notify.yaml b/.github/workflows/matrix_notify.yaml index fe4672808..f1583f11a 100644 --- a/.github/workflows/matrix_notify.yaml +++ b/.github/workflows/matrix_notify.yaml @@ -8,6 +8,7 @@ on: jobs: notify: + if: ${{ (github.event_name == 'issues' && github.event.issue.user.login != 'krille-chan') || (github.event_name == 'pull_request_target' && github.event.pull_request.user.login != 'krille-chan') }} runs-on: ubuntu-latest steps: - name: Send notification to Matrix room diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5161a4d83..1b3f5182c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -106,7 +106,7 @@ - + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index e828d1713..51765d1c9 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -35,7 +35,6 @@ ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER) im.fluffychat - chat.fluffy matrix diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index d865b6eee..0dcb6c4c0 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -22,15 +22,15 @@ abstract class AppConfig { static const double columnWidth = 360.0; static const String enablePushTutorial = - 'https://fluffy.chat/faq/#push_without_google_services'; + 'https://fluffychat.im/faq/#push_without_google_services'; static const String encryptionTutorial = - 'https://fluffy.chat/faq/#how_to_use_end_to_end_encryption'; + 'https://fluffychat.im/faq/#how_to_use_end_to_end_encryption'; static const String startChatTutorial = - 'https://fluffy.chat/faq/#how_do_i_find_other_users'; + 'https://fluffychat.im/faq/#how_do_i_find_other_users'; static const String howDoIGetStickersTutorial = - 'https://fluffy.chat/faq/#how_do_i_get_stickers'; + 'https://fluffychat.im/faq/#how_do_i_get_stickers'; static const String appId = 'im.fluffychat.FluffyChat'; - static const String appOpenUrlScheme = 'chat.fluffy'; + static const String appOpenUrlScheme = 'im.fluffychat'; static const String sourceCodeUrl = 'https://github.com/krille-chan/fluffychat'; diff --git a/lib/config/routes.dart b/lib/config/routes.dart index a6d2d70ce..6ae9d3b67 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -170,8 +170,14 @@ abstract class AppRoutes { ), GoRoute( path: 'newprivatechat', - pageBuilder: (context, state) => - defaultPageBuilder(context, state, const NewPrivateChat()), + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + NewPrivateChat( + key: ValueKey('new_chat_${state.uri.query}'), + deeplink: state.uri.queryParameters['deeplink'], + ), + ), redirect: loggedOutRedirect, ), GoRoute( diff --git a/lib/config/setting_keys.dart b/lib/config/setting_keys.dart index c623ce6c7..627313ed7 100644 --- a/lib/config/setting_keys.dart +++ b/lib/config/setting_keys.dart @@ -56,16 +56,16 @@ enum AppSettings { enableMatrixNativeOIDC('chat.fluffy.enable_matrix_native_oidc', false), presetHomeserver('chat.fluffy.preset_homeserver', ''), welcomeText('chat.fluffy.welcome_text', ''), - website('chat.fluffy.website_url', 'https://fluffy.chat'), + website('chat.fluffy.website_url', 'https://fluffychat.im'), logoUrl( 'chat.fluffy.logo_url', - 'https://fluffy.chat/assets/favicon.png', + 'https://fluffychat.im/assets/favicon.png', ), privacyPolicy( 'chat.fluffy.privacy_policy_url', - 'https://fluffy.chat/en/privacy', + 'https://fluffychat.im/en/privacy', ), - tos('chat.fluffy.tos_url', 'https://fluffy.chat/en/tos'); + tos('chat.fluffy.tos_url', 'https://fluffychat.im/en/tos'); final String key; final T defaultValue; diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index f2edc232f..f78345d37 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -165,11 +165,11 @@ class AudioPlayerState extends State { : null, ); - if (!kIsWeb) { + final attachmentUrl = widget.event.attachmentOrThumbnailMxcUrl(); + + if (!kIsWeb && attachmentUrl != null) { final tempDir = await getTemporaryDirectory(); - final fileName = Uri.encodeComponent( - widget.event.attachmentOrThumbnailMxcUrl()!.pathSegments.last, - ); + final fileName = Uri.encodeComponent(attachmentUrl.pathSegments.last); file = File('${tempDir.path}/${fileName}_${matrixFile.name}'); await file.writeAsBytes(matrixFile.bytes); diff --git a/lib/pages/chat/send_file_dialog.dart b/lib/pages/chat/send_file_dialog.dart index 57f124b2c..4e67b338d 100644 --- a/lib/pages/chat/send_file_dialog.dart +++ b/lib/pages/chat/send_file_dialog.dart @@ -1,8 +1,9 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:async/async.dart' show Result; import 'package:cross_file/cross_file.dart'; -import 'package:matrix/matrix.dart'; +import 'package:matrix/matrix.dart' hide Result; import 'package:mime/mime.dart'; import 'package:fluffychat/config/app_config.dart'; @@ -53,8 +54,9 @@ class SendFileDialogState extends State { } scaffoldMessenger.showLoadingSnackBar(l10n.prepareSendingAttachment); Navigator.of(context, rootNavigator: false).pop(); - final clientConfig = await widget.room.client.getConfig(); - final maxUploadSize = clientConfig.mUploadSize ?? 100 * 1000 * 1000; + final clientConfig = await Result.capture(widget.room.client.getConfig()); + final maxUploadSize = + clientConfig.asValue?.value.mUploadSize ?? 100 * 1000 * 1000; for (final xfile in widget.files) { final MatrixFile file; diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index d8751f9cb..75181bf04 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -1,9 +1,9 @@ import 'dart:async'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:app_links/app_links.dart'; import 'package:cross_file/cross_file.dart'; import 'package:flutter_shortcuts_new/flutter_shortcuts_new.dart'; import 'package:go_router/go_router.dart'; @@ -11,6 +11,7 @@ import 'package:matrix/matrix.dart' as sdk; import 'package:matrix/matrix.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pages/chat_list/chat_list_view.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; @@ -71,8 +72,6 @@ class ChatListController extends State StreamSubscription? _intentFileStreamSubscription; - StreamSubscription? _intentUriStreamSubscription; - late ActiveFilter activeFilter; String? _activeSpaceId; @@ -308,6 +307,12 @@ class ChatListController extends State void _processIncomingSharedMedia(List files) { if (files.isEmpty) return; + if (files.singleOrNull?.path.startsWith(AppConfig.deepLinkPrefix) == true) { + return; + } + + inspect(files); + showScaffoldDialog( context: context, builder: (context) => ShareScaffoldDialog( @@ -326,14 +331,6 @@ class ChatListController extends State ); } - Future _processIncomingUris(Uri? uri) async { - if (uri == null) return; - context.go('/rooms'); - WidgetsBinding.instance.addPostFrameCallback((_) { - UrlLauncher(context, uri.toString()).openMatrixToUrl(); - }); - } - void _initReceiveSharingIntent() { if (!PlatformInfos.isMobile) return; @@ -347,11 +344,6 @@ class ChatListController extends State _processIncomingSharedMedia, ); - // For receiving shared Uris - _intentUriStreamSubscription = AppLinks().uriLinkStream.listen( - _processIncomingUris, - ); - if (PlatformInfos.isAndroid) { final shortcuts = FlutterShortcuts(); shortcuts.initialize().then( @@ -394,7 +386,6 @@ class ChatListController extends State void dispose() { _intentDataStreamSubscription?.cancel(); _intentFileStreamSubscription?.cancel(); - _intentUriStreamSubscription?.cancel(); scrollController.removeListener(_onScroll); super.dispose(); } diff --git a/lib/pages/new_private_chat/new_private_chat.dart b/lib/pages/new_private_chat/new_private_chat.dart index 55435cc11..e5d8e202f 100644 --- a/lib/pages/new_private_chat/new_private_chat.dart +++ b/lib/pages/new_private_chat/new_private_chat.dart @@ -17,7 +17,8 @@ import 'package:fluffychat/widgets/matrix.dart'; import '../../widgets/adaptive_dialogs/user_dialog.dart'; class NewPrivateChat extends StatefulWidget { - const NewPrivateChat({super.key}); + final String? deeplink; + const NewPrivateChat({super.key, required this.deeplink}); @override NewPrivateChatController createState() => NewPrivateChatController(); @@ -33,6 +34,18 @@ class NewPrivateChatController extends State { static const Duration _coolDown = Duration(milliseconds: 500); + @override + void initState() { + super.initState(); + + final deeplink = widget.deeplink; + if (deeplink != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + UrlLauncher(context, deeplink).openMatrixToUrl(); + }); + } + } + Future searchUsers([String? input]) async { final searchTerm = input ?? controller.text; if (searchTerm.isEmpty) { diff --git a/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart b/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart index 5848cf545..09e8d6ac6 100644 --- a/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart +++ b/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart @@ -85,7 +85,7 @@ class AdaptiveDialogAction extends StatelessWidget { class AdaptiveDialogInkWell extends StatelessWidget { final Widget child; - final VoidCallback onTap; + final VoidCallback? onTap; final EdgeInsets padding; const AdaptiveDialogInkWell({ @@ -125,7 +125,7 @@ class AdaptiveDialogInkWell extends StatelessWidget { class AdaptiveIconTextButton extends StatelessWidget { final String label; final IconData icon; - final VoidCallback onTap; + final VoidCallback? onTap; const AdaptiveIconTextButton({ super.key, required this.label, diff --git a/lib/widgets/adaptive_dialogs/user_dialog.dart b/lib/widgets/adaptive_dialogs/user_dialog.dart index 4be6ba9d6..674bd9c1f 100644 --- a/lib/widgets/adaptive_dialogs/user_dialog.dart +++ b/lib/widgets/adaptive_dialogs/user_dialog.dart @@ -195,35 +195,39 @@ class UserDialog extends StatelessWidget { AdaptiveIconTextButton( label: L10n.of(context).block, icon: Icons.block_outlined, - onTap: () { - final router = GoRouter.of(context); - Navigator.of(context).pop(); - router.go( - '/rooms/settings/security/ignorelist', - extra: profile.userId, - ); - }, + onTap: client.userID == profile.userId + ? null + : () { + final router = GoRouter.of(context); + Navigator.of(context).pop(); + router.go( + '/rooms/settings/security/ignorelist', + extra: profile.userId, + ); + }, ), AdaptiveIconTextButton( label: L10n.of(context).report, icon: Icons.gavel_outlined, - onTap: () async { - Navigator.of(context).pop(); - final reason = await showTextInputDialog( - context: context, - title: L10n.of(context).whyDoYouWantToReportThis, - okLabel: L10n.of(context).report, - cancelLabel: L10n.of(context).cancel, - hintText: L10n.of(context).reason, - ); - if (reason == null || reason.isEmpty) return; - await showFutureLoadingDialog( - context: context, - future: () => Matrix.of( - context, - ).client.reportUser(profile.userId, reason), - ); - }, + onTap: client.userID == profile.userId + ? null + : () async { + Navigator.of(context).pop(); + final reason = await showTextInputDialog( + context: context, + title: L10n.of(context).whyDoYouWantToReportThis, + okLabel: L10n.of(context).report, + cancelLabel: L10n.of(context).cancel, + hintText: L10n.of(context).reason, + ); + if (reason == null || reason.isEmpty) return; + await showFutureLoadingDialog( + context: context, + future: () => Matrix.of( + context, + ).client.reportUser(profile.userId, reason), + ); + }, ), AdaptiveIconTextButton( label: L10n.of(context).share, @@ -236,17 +240,19 @@ class UserDialog extends StatelessWidget { ], ), AdaptiveDialogInkWell( - onTap: () async { - final router = GoRouter.of(context); - final roomIdResult = await showFutureLoadingDialog( - context: context, - future: () => client.startDirectChat(profile.userId), - ); - final roomId = roomIdResult.result; - if (roomId == null) return; - if (context.mounted) Navigator.of(context).pop(); - router.go('/rooms/$roomId'); - }, + onTap: client.userID == profile.userId + ? null + : () async { + final router = GoRouter.of(context); + final roomIdResult = await showFutureLoadingDialog( + context: context, + future: () => client.startDirectChat(profile.userId), + ); + final roomId = roomIdResult.result; + if (roomId == null) return; + if (context.mounted) Navigator.of(context).pop(); + router.go('/rooms/$roomId'); + }, child: Text( directChatRoomId == null ? L10n.of(context).createNewChat diff --git a/lib/widgets/fluffy_chat_app.dart b/lib/widgets/fluffy_chat_app.dart index 4a72d07dd..af7803792 100644 --- a/lib/widgets/fluffy_chat_app.dart +++ b/lib/widgets/fluffy_chat_app.dart @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/routes.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; @@ -37,6 +38,12 @@ class FluffyChatApp extends StatelessWidget { static final GoRouter router = GoRouter( routes: AppRoutes.routes, debugLogDiagnostics: true, + redirect: (context, state) { + if (state.uri.toString().startsWith(AppConfig.deepLinkPrefix)) { + return '/rooms/newprivatechat?deeplink=${state.uri}'; + } + return null; + }, ); @override diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index deccda1dc..b586adbbf 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -45,9 +44,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_webrtc_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWebRTCPlugin"); flutter_web_r_t_c_plugin_register_with_registrar(flutter_webrtc_registrar); - g_autoptr(FlPluginRegistrar) gtk_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); - gtk_plugin_register_with_registrar(gtk_registrar); g_autoptr(FlPluginRegistrar) handy_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "HandyWindowPlugin"); handy_window_plugin_register_with_registrar(handy_window_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 53413056c..95cd5f009 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -10,7 +10,6 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_linux flutter_secure_storage_linux flutter_webrtc - gtk handy_window record_linux screen_retriever_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 0e1ab0cac..a334837f6 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,7 +5,6 @@ import FlutterMacOS import Foundation -import app_links import audio_session import desktop_drop import desktop_webview_window @@ -36,7 +35,6 @@ import window_manager import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin")) DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 982b471c2..78d1b7508 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,38 +41,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" - app_links: - dependency: "direct main" - description: - name: app_links - sha256: "5f88447519add627fe1cbcab4fd1da3d4fed15b9baf29f28b22535c95ecee3e8" - url: "https://pub.dev" - source: hosted - version: "6.4.1" - app_links_linux: - dependency: transitive - description: - name: app_links_linux - sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 - url: "https://pub.dev" - source: hosted - version: "1.0.3" - app_links_platform_interface: - dependency: transitive - description: - name: app_links_platform_interface - sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - app_links_web: - dependency: transitive - description: - name: app_links_web - sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 - url: "https://pub.dev" - source: hosted - version: "1.0.4" archive: dependency: "direct main" description: @@ -807,14 +775,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.8" - gtk: - dependency: transitive - description: - name: gtk - sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c - url: "https://pub.dev" - source: hosted - version: "2.1.0" handy_window: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index aeeb8e91c..99115e514 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,6 @@ environment: dependencies: animations: ^2.1.1 - app_links: ^6.4.1 archive: ^4.0.7 async: ^2.11.0 badges: ^3.1.2 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 0e75c6434..42b9ae094 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,7 +6,6 @@ #include "generated_plugin_registrant.h" -#include #include #include #include @@ -26,8 +25,6 @@ #include void RegisterPlugins(flutter::PluginRegistry* registry) { - AppLinksPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("AppLinksPluginCApi")); DesktopDropPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("DesktopDropPlugin")); DesktopWebviewWindowPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 307090774..93b91c2eb 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - app_links desktop_drop desktop_webview_window dynamic_color