feat: enable joining space via link on mobile (#4712)

This commit is contained in:
ggurdin 2025-11-20 12:15:47 -05:00 committed by GitHub
parent cddad03ff9
commit 0c7813dc8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 74 additions and 14 deletions

View file

@ -109,6 +109,20 @@
<data android:mimeType="*/*" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="app.pangea.chat" />
<data
android:scheme="https"
android:host="app.staging.pangea.chat" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />

View file

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
<string>13.0</string>
</dict>
</plist>

View file

@ -7,6 +7,7 @@
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:app.pangea.chat</string>
<string>applinks:app.staging.pangea.chat</string>
</array>
<key>com.apple.security.application-groups</key>
<array>

View file

@ -4,7 +4,6 @@ import 'package:flutter/foundation.dart';
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';
@ -105,7 +104,9 @@ class ChatListController extends State<ChatList>
StreamSubscription? _intentFileStreamSubscription;
StreamSubscription? _intentUriStreamSubscription;
// #Pangea
// StreamSubscription? _intentUriStreamSubscription;
// Pangea#
ActiveFilter activeFilter = AppConfig.separateChatTypes
? ActiveFilter.messages
@ -463,6 +464,9 @@ class ChatListController extends State<ChatList>
void _processIncomingSharedMedia(List<SharedMediaFile> files) {
if (files.isEmpty) return;
// #Pangea
if (files.every((f) => f.type == SharedMediaType.url)) return;
// Pangea#
showScaffoldDialog(
context: context,
@ -487,13 +491,15 @@ class ChatListController extends State<ChatList>
);
}
void _processIncomingUris(Uri? uri) async {
if (uri == null) return;
context.go('/rooms');
WidgetsBinding.instance.addPostFrameCallback((_) {
UrlLauncher(context, uri.toString()).openMatrixToUrl();
});
}
// #Pangea
// void _processIncomingUris(Uri? uri) async {
// if (uri == null) return;
// context.go('/rooms');
// WidgetsBinding.instance.addPostFrameCallback((_) {
// UrlLauncher(context, uri.toString()).openMatrixToUrl();
// });
// }
// Pangea#
void _initReceiveSharingIntent() {
if (!PlatformInfos.isMobile) return;
@ -508,9 +514,11 @@ class ChatListController extends State<ChatList>
.getInitialMedia()
.then(_processIncomingSharedMedia);
// For receiving shared Uris
_intentUriStreamSubscription =
AppLinks().uriLinkStream.listen(_processIncomingUris);
// #Pangea
// // For receiving shared Uris
// _intentUriStreamSubscription =
// AppLinks().uriLinkStream.listen(_processIncomingUris);
// Pangea#
if (PlatformInfos.isAndroid) {
final shortcuts = FlutterShortcuts();
@ -686,12 +694,14 @@ class ChatListController extends State<ChatList>
void dispose() {
_intentDataStreamSubscription?.cancel();
_intentFileStreamSubscription?.cancel();
_intentUriStreamSubscription?.cancel();
//#Pangea
// _intentUriStreamSubscription?.cancel();
_invitedSpaceSubscription?.cancel();
_roomCapacitySubscription?.cancel();
MatrixState.pangeaController.subscriptionController.subscriptionNotifier
.removeListener(_onSubscribe);
MatrixState.pangeaController.spaceCodeController.codeNotifier
.removeListener(_onCacheSpaceCode);
//Pangea#
scrollController.removeListener(_onScroll);
super.dispose();
@ -1104,8 +1114,17 @@ class ChatListController extends State<ChatList>
if (mounted) {
MatrixState.pangeaController.spaceCodeController
.joinCachedSpaceCode(context);
MatrixState.pangeaController.spaceCodeController.codeNotifier
.addListener(_onCacheSpaceCode);
}
}
void _onCacheSpaceCode() {
if (!mounted) return;
MatrixState.pangeaController.spaceCodeController.joinCachedSpaceCode(
context,
);
}
// Pangea#
void setActiveFilter(ActiveFilter filter) {

View file

@ -13,9 +13,11 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/constants/local.key.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
import 'package:fluffychat/pangea/spaces/utils/knock_space_extension.dart';
import 'package:fluffychat/pangea/spaces/widgets/too_many_requests_dialog.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../common/controllers/base_controller.dart';
class NotFoundException implements Exception {}
@ -25,6 +27,7 @@ class SpaceCodeController extends BaseController {
static final GetStorage _spaceStorage = GetStorage('class_storage');
Completer<void> initCompleter = Completer<void>();
ValueNotifier<String?> codeNotifier = ValueNotifier<String?>(null);
SpaceCodeController(PangeaController pangeaController) : super() {
_pangeaController = pangeaController;
@ -39,6 +42,7 @@ class SpaceCodeController extends BaseController {
PLocalKey.cachedSpaceCodeToJoin,
code,
);
codeNotifier.value = code;
}
String? get justInputtedCode =>
@ -176,4 +180,14 @@ class SpaceCodeController extends BaseController {
await room.requestParticipants();
}
}
static Future<void> onOpenAppViaUrl(Uri url) async {
if (url.fragment.isEmpty) return;
final fragment = Uri.parse(url.fragment);
final code = fragment.queryParameters[SpaceConstants.classCode];
if (code != null && fragment.path.contains('join_with_link')) {
await MatrixState.pangeaController.spaceCodeController
.cacheSpaceCode(code);
}
}
}

View file

@ -4,6 +4,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:app_links/app_links.dart';
import 'package:collection/collection.dart';
import 'package:desktop_notifications/desktop_notifications.dart';
import 'package:http/http.dart' as http;
@ -23,6 +24,7 @@ import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/any_state_holder.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/learning_settings/utils/locale_provider.dart';
import 'package:fluffychat/pangea/spaces/controllers/space_code_controller.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -71,6 +73,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
// #Pangea
static late PangeaController pangeaController;
static PangeaAnyState pAnyState = PangeaAnyState();
late StreamSubscription? _uriListener;
// Pangea#
SharedPreferences get store => widget.store;
@ -275,6 +278,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
_setAppLanguage();
_setLanguageListener();
});
_uriListener = AppLinks().uriLinkStream.listen(_processIncomingUris);
// Pangea#
}
@ -562,6 +566,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
linuxNotifications?.close();
// #Pangea
_languageListener?.cancel();
_uriListener?.cancel();
// Pangea#
super.dispose();
@ -602,6 +607,13 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
final file = MatrixFile(bytes: exportBytes, name: exportFileName);
file.save(context);
}
// #Pangea
Future<void> _processIncomingUris(Uri? uri) async {
if (uri == null) return;
await SpaceCodeController.onOpenAppViaUrl(uri);
}
// Pangea#
}
class _AccountBundleWithClient {