fix: display WebRTC call overlay in web

This commit is contained in:
Lanna Michalke 2022-02-19 08:27:03 +00:00 committed by Krille Fear
parent 5b91bc3a27
commit e207b26008
7 changed files with 99 additions and 29 deletions

View File

@ -175,6 +175,7 @@ class ChatListController extends State<ChatList> {
scrollController.addListener(_onScroll); scrollController.addListener(_onScroll);
_waitForFirstSync(); _waitForFirstSync();
_hackyWebRTCFixForWeb();
super.initState(); super.initState();
} }
@ -576,6 +577,10 @@ class ChatListController extends State<ChatList> {
Matrix.of(context).navigatorContext = context; Matrix.of(context).navigatorContext = context;
return ChatListView(this); return ChatListView(this);
} }
void _hackyWebRTCFixForWeb() {
Matrix.of(context).voipPlugin?.context = context;
}
} }
enum EditBundleAction { addToBundle, removeFromBundle } enum EditBundleAction { addToBundle, removeFromBundle }

View File

@ -1,12 +1,12 @@
import 'dart:core'; import 'dart:core';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart';
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart' as webrtc_impl; import 'package:flutter_webrtc/flutter_webrtc.dart' as webrtc_impl;
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:webrtc_interface/webrtc_interface.dart'; import 'package:webrtc_interface/webrtc_interface.dart' hide Navigator;
import 'package:fluffychat/pages/dialer/dialer.dart'; import 'package:fluffychat/pages/dialer/dialer.dart';
import '../../utils/voip/user_media_manager.dart'; import '../../utils/voip/user_media_manager.dart';
@ -14,10 +14,14 @@ import '../../utils/voip/user_media_manager.dart';
class VoipPlugin extends WidgetsBindingObserver implements WebRTCDelegate { class VoipPlugin extends WidgetsBindingObserver implements WebRTCDelegate {
VoipPlugin({required this.client, required this.context}) { VoipPlugin({required this.client, required this.context}) {
voip = VoIP(client, this); voip = VoIP(client, this);
Connectivity() try {
.onConnectivityChanged Connectivity()
.listen(_handleNetworkChanged) .onConnectivityChanged
.onError((e) => _currentConnectivity = ConnectivityResult.none); .listen(_handleNetworkChanged)
.onError((e) => _currentConnectivity = ConnectivityResult.none);
} catch (e, s) {
Logs().w('Could not subscribe network updates', e, s);
}
Connectivity() Connectivity()
.checkConnectivity() .checkConnectivity()
.then((result) => _currentConnectivity = result) .then((result) => _currentConnectivity = result)
@ -39,7 +43,11 @@ class VoipPlugin extends WidgetsBindingObserver implements WebRTCDelegate {
ValueChanged<CallSession>? onIncomingCall; ValueChanged<CallSession>? onIncomingCall;
OverlayEntry? overlayEntry; OverlayEntry? overlayEntry;
final BuildContext context; // hacky workaround: in order to have [Overlay.of] working on web, the context
// mus explicitly be re-assigned
//
// hours wasted: 5
BuildContext context;
void _handleNetworkChanged(ConnectivityResult result) async { void _handleNetworkChanged(ConnectivityResult result) async {
/// Got a new connectivity status! /// Got a new connectivity status!
@ -64,18 +72,33 @@ class VoipPlugin extends WidgetsBindingObserver implements WebRTCDelegate {
Logs().w('[VOIP] addCallingOverlay: The call session already exists?'); Logs().w('[VOIP] addCallingOverlay: The call session already exists?');
overlayEntry?.remove(); overlayEntry?.remove();
} }
overlayEntry = OverlayEntry( // Overlay.of(context) is broken on web
builder: (_) => Calling( // falling back on a dialog
if (kIsWeb) {
showDialog(
context: context,
builder: (context) => Calling(
context: context, context: context,
client: client, client: client,
callId: callId, callId: callId,
call: call, call: call,
onClear: () { onClear: () => Navigator.of(context).pop(),
overlayEntry?.remove(); ),
overlayEntry = null; );
}), } else {
); overlayEntry = OverlayEntry(
Overlay.of(context)!.insert(overlayEntry!); builder: (_) => Calling(
context: context,
client: client,
callId: callId,
call: call,
onClear: () {
overlayEntry?.remove();
overlayEntry = null;
}),
);
Overlay.of(context)!.insert(overlayEntry!);
}
} }
@override @override

View File

@ -83,10 +83,13 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
return widget.clients[_activeClient]; return widget.clients[_activeClient];
} }
bool get webrtcIsSupported => PlatformInfos.isMobile; bool get webrtcIsSupported =>
kIsWeb ||
PlatformInfos.isMobile ||
PlatformInfos.isWindows ||
PlatformInfos.isMacOS;
VoipPlugin? get voipPlugin => VoipPlugin? voipPlugin;
webrtcIsSupported ? VoipPlugin(client: client, context: context) : null;
bool get isMultiAccount => widget.clients.length > 1; bool get isMultiAccount => widget.clients.length > 1;
@ -100,6 +103,8 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
final i = widget.clients.indexWhere((c) => c == cl); final i = widget.clients.indexWhere((c) => c == cl);
if (i != -1) { if (i != -1) {
_activeClient = i; _activeClient = i;
// TODO: Multi-client VoiP support
createVoipPlugin();
} else { } else {
Logs().w('Tried to set an unknown client ${cl!.userID} as active'); Logs().w('Tried to set an unknown client ${cl!.userID} as active');
} }
@ -172,6 +177,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
widget.clients.firstWhereOrNull((c) => c.clientName == name); widget.clients.firstWhereOrNull((c) => c.clientName == name);
Map<String, dynamic>? get shareContent => _shareContent; Map<String, dynamic>? get shareContent => _shareContent;
set shareContent(Map<String, dynamic>? content) { set shareContent(Map<String, dynamic>? content) {
_shareContent = content; _shareContent = content;
onShareContentChanged.add(_shareContent); onShareContentChanged.add(_shareContent);
@ -216,6 +222,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
String? _cachedPassword; String? _cachedPassword;
Timer? _cachedPasswordClearTimer; Timer? _cachedPasswordClearTimer;
String? get cachedPassword => _cachedPassword; String? get cachedPassword => _cachedPassword;
set cachedPassword(String? p) { set cachedPassword(String? p) {
@ -420,6 +427,13 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
), ),
); );
} }
createVoipPlugin();
}
void createVoipPlugin() {
voipPlugin =
webrtcIsSupported ? VoipPlugin(client: client, context: context) : null;
} }
bool _firstStartup = true; bool _firstStartup = true;
@ -534,5 +548,6 @@ class FixedThreepidCreds extends ThreepidCreds {
class _AccountBundleWithClient { class _AccountBundleWithClient {
final Client? client; final Client? client;
final AccountBundle? bundle; final AccountBundle? bundle;
_AccountBundleWithClient({this.client, this.bundle}); _AccountBundleWithClient({this.client, this.bundle});
} }

View File

@ -10,6 +10,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_linux url_launcher_linux
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST}) foreach(plugin ${FLUTTER_PLUGIN_LIST})
@ -18,3 +21,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>) list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin) endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View File

@ -226,12 +226,14 @@ packages:
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
connectivity_plus_web: connectivity_plus_web:
dependency: transitive dependency: "direct overridden"
description: description:
name: connectivity_plus_web path: "packages/connectivity_plus/connectivity_plus_web"
url: "https://pub.dartlang.org" ref: a04401cb48abe92d138c0e9288b360739994a9e9
source: hosted resolved-ref: a04401cb48abe92d138c0e9288b360739994a9e9
version: "1.2.0" url: "https://github.com/TheOneWithTheBraid/plus_plugins.git"
source: git
version: "1.2.1"
connectivity_plus_windows: connectivity_plus_windows:
dependency: transitive dependency: transitive
description: description:
@ -888,7 +890,7 @@ packages:
name: js name: js
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.3" version: "0.6.4"
latlong2: latlong2:
dependency: transitive dependency: transitive
description: description:
@ -1105,7 +1107,7 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.8.1"
path_drawing: path_drawing:
dependency: transitive dependency: transitive
description: description:
@ -1558,21 +1560,21 @@ packages:
name: test name: test
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.19.5" version: "1.20.1"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.8" version: "0.4.9"
test_core: test_core:
dependency: transitive dependency: transitive
description: description:
name: test_core name: test_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.9" version: "0.4.11"
timezone: timezone:
dependency: transitive dependency: transitive
description: description:
@ -1896,5 +1898,5 @@ packages:
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
sdks: sdks:
dart: ">=2.15.1 <3.0.0" dart: ">=2.16.0-100.0.dev <3.0.0"
flutter: ">=2.8.0" flutter: ">=2.8.0"

View File

@ -121,6 +121,15 @@ flutter:
- asset: fonts/NotoEmoji/NotoColorEmoji.ttf - asset: fonts/NotoEmoji/NotoColorEmoji.ttf
dependency_overrides: dependency_overrides:
# Necessary for webRTC on web.
# Fix for stream fallback for unsupported browsers:
# https://github.com/fluttercommunity/plus_plugins/pull/746
# Upstream pull request: https://github.com/fluttercommunity/plus_plugins/pull/746
connectivity_plus_web:
git:
url: https://github.com/TheOneWithTheBraid/plus_plugins.git
ref: a04401cb48abe92d138c0e9288b360739994a9e9
path: packages/connectivity_plus/connectivity_plus_web
dbus: ^0.7.1 dbus: ^0.7.1
geolocator_android: geolocator_android:
hosted: hosted:

View File

@ -12,6 +12,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_windows url_launcher_windows
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST}) foreach(plugin ${FLUTTER_PLUGIN_LIST})
@ -20,3 +23,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>) list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin) endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)