Implement jitsi
This commit is contained in:
parent
4852fd42ad
commit
7f93dd2c97
|
@ -6,6 +6,7 @@ import 'package:fluffychat/utils/app_route.dart';
|
|||
import 'package:fluffychat/views/chat_details.dart';
|
||||
import 'package:fluffychat/views/chat_list.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'dialogs/simple_dialogs.dart';
|
||||
import 'matrix.dart';
|
||||
|
@ -29,6 +30,18 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
void startCallAction(BuildContext context) async {
|
||||
final url =
|
||||
'${Matrix.of(context).jitsiInstance}${Uri.encodeComponent(widget.room.id.localpart)}';
|
||||
final success = await Matrix.of(context)
|
||||
.tryRequestWithLoadingDialog(widget.room.sendEvent({
|
||||
'msgtype': Matrix.callNamespace,
|
||||
'body': url,
|
||||
}));
|
||||
if (success == false) return;
|
||||
await launch(url);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
notificationChangeSub ??= Matrix.of(context)
|
||||
|
@ -49,6 +62,10 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
value: "unmute",
|
||||
child: Text(I18n.of(context).unmuteChat),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: "call",
|
||||
child: Text(I18n.of(context).videoCall),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: "leave",
|
||||
child: Text(I18n.of(context).leave),
|
||||
|
@ -86,6 +103,9 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
await Matrix.of(context).tryRequestWithLoadingDialog(
|
||||
widget.room.setPushRuleState(PushRuleState.notify));
|
||||
break;
|
||||
case "call":
|
||||
startCallAction(context);
|
||||
break;
|
||||
case "details":
|
||||
await Navigator.of(context).push(
|
||||
AppRoute.defaultRoute(
|
||||
|
|
|
@ -26,6 +26,7 @@ class SimpleDialogs {
|
|||
content: TextField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
autocorrect: false,
|
||||
onSubmitted: (s) {
|
||||
input = s;
|
||||
Navigator.of(context).pop();
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:localstorage/localstorage.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../i18n/i18n.dart';
|
||||
import '../utils/app_route.dart';
|
||||
|
@ -18,8 +19,11 @@ import '../utils/event_extension.dart';
|
|||
import '../utils/famedlysdk_store.dart';
|
||||
import '../utils/room_extension.dart';
|
||||
import '../views/chat.dart';
|
||||
import 'avatar.dart';
|
||||
|
||||
class Matrix extends StatefulWidget {
|
||||
static const String callNamespace = 'chat.fluffy.jitsi_call';
|
||||
|
||||
final Widget child;
|
||||
|
||||
final String clientName;
|
||||
|
@ -52,6 +56,8 @@ class MatrixState extends State<Matrix> {
|
|||
String activeRoomId;
|
||||
File wallpaper;
|
||||
|
||||
String jitsiInstance = 'https://meet.jit.si/';
|
||||
|
||||
void clean() async {
|
||||
if (!kIsWeb) return;
|
||||
|
||||
|
@ -343,12 +349,73 @@ class MatrixState extends State<Matrix> {
|
|||
};
|
||||
|
||||
StreamSubscription onRoomKeyRequestSub;
|
||||
StreamSubscription onJitsiCallSub;
|
||||
|
||||
void onJitsiCall(EventUpdate eventUpdate) {
|
||||
final event = Event.fromJson(
|
||||
eventUpdate.content, client.getRoomById(eventUpdate.roomID));
|
||||
if (DateTime.now().millisecondsSinceEpoch -
|
||||
event.time.millisecondsSinceEpoch >
|
||||
1000 * 60 * 5) {
|
||||
return;
|
||||
}
|
||||
final senderName = event.sender.calcDisplayname();
|
||||
final senderAvatar = event.sender.avatarUrl;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: ListTile(
|
||||
contentPadding: EdgeInsets.all(0),
|
||||
leading: Avatar(senderAvatar, senderName),
|
||||
title: Text(
|
||||
senderName,
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
subtitle:
|
||||
event.room.isDirectChat ? null : Text(event.room.displayname),
|
||||
),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Divider(),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Spacer(),
|
||||
FloatingActionButton(
|
||||
backgroundColor: Colors.red,
|
||||
child: Icon(Icons.phone_missed),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
Spacer(),
|
||||
FloatingActionButton(
|
||||
backgroundColor: Colors.green,
|
||||
child: Icon(Icons.phone),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
launch(event.body);
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if (widget.client == null) {
|
||||
debugPrint("[Matrix] Init matrix client");
|
||||
client = Client(widget.clientName, debug: false);
|
||||
onJitsiCallSub ??= client.onEvent.stream
|
||||
.where((e) =>
|
||||
e.eventType == 'm.room.message' &&
|
||||
e.content['content']['msgtype'] == Matrix.callNamespace &&
|
||||
e.content['sender'] != client.userID)
|
||||
.listen(onJitsiCall);
|
||||
onRoomKeyRequestSub ??=
|
||||
client.onRoomKeyRequest.stream.listen((RoomKeyRequest request) async {
|
||||
final Room room = request.room;
|
||||
|
@ -368,6 +435,9 @@ class MatrixState extends State<Matrix> {
|
|||
client = widget.client;
|
||||
}
|
||||
if (client.storeAPI != null) {
|
||||
client.storeAPI
|
||||
.getItem("chat.fluffy.jitsi_instance")
|
||||
.then((final instance) => jitsiInstance = instance ?? jitsiInstance);
|
||||
client.storeAPI.getItem("chat.fluffy.wallpaper").then((final path) async {
|
||||
if (path == null) return;
|
||||
final file = File(path);
|
||||
|
@ -382,6 +452,7 @@ class MatrixState extends State<Matrix> {
|
|||
@override
|
||||
void dispose() {
|
||||
onRoomKeyRequestSub?.cancel();
|
||||
onJitsiCallSub?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,19 @@ class MessageContent extends StatelessWidget {
|
|||
case MessageTypes.Notice:
|
||||
case MessageTypes.Emote:
|
||||
default:
|
||||
if (event.content['msgtype'] == Matrix.callNamespace) {
|
||||
return RaisedButton(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Icon(Icons.phone),
|
||||
Text(I18n.of(context).videoCall),
|
||||
],
|
||||
),
|
||||
onPressed: () => launch(event.body),
|
||||
);
|
||||
}
|
||||
return LinkText(
|
||||
text: event.getLocalizedBody(context, hideReply: true),
|
||||
textStyle: TextStyle(
|
||||
|
|
|
@ -371,6 +371,8 @@ class I18n {
|
|||
|
||||
String get isTyping => Intl.message("is typing...");
|
||||
|
||||
String get editJitsiInstance => Intl.message('Edit Jitsi instance');
|
||||
|
||||
String joinedTheChat(String username) => Intl.message(
|
||||
"$username joined the chat",
|
||||
name: "joinedTheChat",
|
||||
|
@ -714,6 +716,8 @@ class I18n {
|
|||
|
||||
String get verify => Intl.message("Verify");
|
||||
|
||||
String get videoCall => Intl.message('Video call');
|
||||
|
||||
String get visibleForAllParticipants =>
|
||||
Intl.message("Visible for all participants");
|
||||
|
||||
|
|
|
@ -49,6 +49,21 @@ class _SettingsState extends State<Settings> {
|
|||
AppRoute.defaultRoute(context, SignUp()), (r) => false);
|
||||
}
|
||||
|
||||
void setJitsiInstanceAction(BuildContext context) async {
|
||||
var jitsi = await SimpleDialogs(context).enterText(
|
||||
titleText: I18n.of(context).editJitsiInstance,
|
||||
hintText: Matrix.of(context).jitsiInstance,
|
||||
labelText: I18n.of(context).editJitsiInstance,
|
||||
);
|
||||
if (jitsi == null) return;
|
||||
if (!jitsi.endsWith('/')) {
|
||||
jitsi += '/';
|
||||
}
|
||||
final MatrixState matrix = Matrix.of(context);
|
||||
await matrix.client.storeAPI.setItem('chat.fluffy.jitsi_instance', jitsi);
|
||||
matrix.jitsiInstance = jitsi;
|
||||
}
|
||||
|
||||
void setDisplaynameAction(BuildContext context) async {
|
||||
final String displayname = await SimpleDialogs(context).enterText(
|
||||
titleText: I18n.of(context).editDisplayname,
|
||||
|
@ -205,6 +220,12 @@ class _SettingsState extends State<Settings> {
|
|||
subtitle: Text(profile?.displayname ?? client.userID.localpart),
|
||||
onTap: () => setDisplaynameAction(context),
|
||||
),
|
||||
ListTile(
|
||||
trailing: Icon(Icons.phone),
|
||||
title: Text(I18n.of(context).editJitsiInstance),
|
||||
subtitle: Text(Matrix.of(context).jitsiInstance),
|
||||
onTap: () => setJitsiInstanceAction(context),
|
||||
),
|
||||
ListTile(
|
||||
trailing: Icon(Icons.devices_other),
|
||||
title: Text(I18n.of(context).devices),
|
||||
|
|
37
pubspec.lock
37
pubspec.lock
|
@ -21,28 +21,28 @@ packages:
|
|||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.13"
|
||||
version: "2.0.11"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
version: "1.5.2"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "1.0.5"
|
||||
bubble:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -63,14 +63,14 @@ packages:
|
|||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
version: "1.1.2"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.12"
|
||||
version: "1.14.11"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -91,7 +91,7 @@ packages:
|
|||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.3"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -260,7 +260,7 @@ packages:
|
|||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.12"
|
||||
version: "2.1.4"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -274,7 +274,7 @@ packages:
|
|||
name: intl
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.16.1"
|
||||
version: "0.16.0"
|
||||
intl_translation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -502,7 +502,7 @@ packages:
|
|||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "2.0.5"
|
||||
receive_sharing_intent:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -570,7 +570,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.5.5"
|
||||
sqflite:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -619,21 +619,21 @@ packages:
|
|||
name: test
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.13.0"
|
||||
version: "1.9.4"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.15"
|
||||
version: "0.2.11"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
version: "0.2.15"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -718,13 +718,6 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webkit_inspection_protocol
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.0+1"
|
||||
webview_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -738,7 +731,7 @@ packages:
|
|||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.6.1"
|
||||
version: "3.5.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
Loading…
Reference in a new issue