feat: allow to create widgets

- supported widget types: therpad, jitsi, video, custom
- update Matrix SDK

Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
This commit is contained in:
TheOneWithTheBraid 2022-03-23 14:09:35 +01:00
parent d1185e8499
commit edc2955408
9 changed files with 241 additions and 18 deletions

View File

@ -2759,5 +2759,15 @@
} }
}, },
"nextAccount": "Next account", "nextAccount": "Next account",
"previousAccount": "Previous account" "previousAccount": "Previous account",
"editWidgets": "Edit widgets",
"addWidget": "Add widget",
"widgetVideo": "Video",
"widgetEtherpad": "Text note",
"widgetJitsi": "Jitsi Meet",
"widgetCustom": "Custom",
"widgetName": "Name",
"widgetUrlError": "This is not a valid URL.",
"widgetNameError": "Please provide a display name.",
"errorAddingWidget": "Error adding the widget."
} }

View File

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix/widget.dart';
import 'package:fluffychat/pages/chat/add_widget_tile_view.dart';
class AddWidgetTile extends StatefulWidget {
final Room room;
const AddWidgetTile({Key? key, required this.room}) : super(key: key);
@override
State<AddWidgetTile> createState() => AddWidgetTileState();
}
class AddWidgetTileState extends State<AddWidgetTile> {
final TextEditingController urlController = TextEditingController();
final TextEditingController nameController = TextEditingController();
String widgetType = 'm.etherpad';
late final bool initiallyExpanded;
String? nameError;
String? urlError;
@override
void initState() {
initiallyExpanded = widget.room.widgets.isEmpty;
super.initState();
}
void setWidgetType(String value) => setState(() => widgetType = value);
void addWidget() {
try {
nameError = null;
urlError = null;
final room = widget.room;
final name = nameController.text;
final uri = Uri.tryParse(urlController.text);
if (name.length < 3) {
setState(() {
nameError = L10n.of(context)!.widgetNameError;
});
return;
}
if (uri == null || uri.scheme != 'https') {
setState(() {
urlError = L10n.of(context)!.widgetUrlError;
});
return;
}
setState(() {});
late MatrixWidget matrixWidget;
switch (widgetType) {
case 'm.etherpad':
matrixWidget = MatrixWidget.etherpad(room, name, uri);
break;
case 'm.jitsi':
matrixWidget = MatrixWidget.jitsi(room, name, uri);
break;
case 'm.video':
matrixWidget = MatrixWidget.video(room, name, uri);
break;
default:
matrixWidget = MatrixWidget.custom(room, name, uri);
break;
}
widget.room.addWidget(matrixWidget);
Navigator.of(context).pop();
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context)!.errorAddingWidget)));
}
}
@override
Widget build(BuildContext context) => AddWidgetTileView(controller: this);
}

View File

@ -0,0 +1,71 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pages/chat/add_widget_tile.dart';
class AddWidgetTileView extends StatelessWidget {
final AddWidgetTileState controller;
const AddWidgetTileView({Key? key, required this.controller})
: super(key: key);
@override
Widget build(BuildContext context) {
return ExpansionTile(
title: Text(L10n.of(context)!.addWidget),
leading: const Icon(Icons.add),
initiallyExpanded: controller.initiallyExpanded,
children: [
CupertinoSegmentedControl(
groupValue: controller.widgetType,
padding: const EdgeInsets.all(8),
children: {
'm.etherpad': Text(L10n.of(context)!.widgetEtherpad),
'm.jitsi': Text(L10n.of(context)!.widgetJitsi),
'm.video': Text(L10n.of(context)!.widgetVideo),
'm.custom': Text(L10n.of(context)!.widgetCustom),
}.map((key, value) => MapEntry(
key,
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: value,
))),
onValueChanged: controller.setWidgetType,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: controller.nameController,
autofocus: true,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.label),
label: Text(L10n.of(context)!.widgetName),
errorText: controller.nameError,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: controller.urlController,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.add_link),
label: Text(L10n.of(context)!.link),
errorText: controller.urlError,
),
),
),
ButtonBar(
children: [
TextButton(
onPressed: controller.addWidget,
child: Text(L10n.of(context)!.addWidget),
),
],
)
],
);
}
}

View File

@ -4,11 +4,14 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:url_launcher/link.dart'; import 'package:url_launcher/link.dart';
import 'edit_widgets_dialog.dart';
class CupertinoWidgetsBottomSheet extends StatelessWidget { class CupertinoWidgetsBottomSheet extends StatelessWidget {
final Room room; final Room room;
const CupertinoWidgetsBottomSheet({Key? key, required this.room}) const CupertinoWidgetsBottomSheet({Key? key, required this.room})
: super(key: key); : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CupertinoActionSheet( return CupertinoActionSheet(
@ -27,8 +30,14 @@ class CupertinoWidgetsBottomSheet extends StatelessWidget {
), ),
), ),
CupertinoActionSheetAction( CupertinoActionSheetAction(
child: Text(L10n.of(context)!.integrationsNotImplemented), child: Text(L10n.of(context)!.editWidgets),
onPressed: () {}, onPressed: () {
Navigator.of(context).pop();
showCupertinoDialog(
context: context,
builder: (context) => EditWidgetsDialog(room: room),
);
},
), ),
CupertinoActionSheetAction( CupertinoActionSheetAction(
child: Text(L10n.of(context)!.cancel), child: Text(L10n.of(context)!.cancel),

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'add_widget_tile.dart';
class EditWidgetsDialog extends StatelessWidget {
final Room room;
const EditWidgetsDialog({Key? key, required this.room}) : super(key: key);
@override
Widget build(BuildContext context) {
return SimpleDialog(
title: Text(L10n.of(context)!.editWidgets),
children: [
...room.widgets.map((e) => ListTile(
title: Text(e.name ?? e.type),
leading: IconButton(
onPressed: () {
room.deleteWidget(e.id!);
Navigator.of(context).pop();
},
icon: const Icon(Icons.delete)),
)),
AddWidgetTile(room: room),
],
);
}
}

View File

@ -4,10 +4,13 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:url_launcher/link.dart'; import 'package:url_launcher/link.dart';
import 'edit_widgets_dialog.dart';
class WidgetsBottomSheet extends StatelessWidget { class WidgetsBottomSheet extends StatelessWidget {
final Room room; final Room room;
const WidgetsBottomSheet({Key? key, required this.room}) : super(key: key); const WidgetsBottomSheet({Key? key, required this.room}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListView.builder( return ListView.builder(
@ -15,8 +18,15 @@ class WidgetsBottomSheet extends StatelessWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (index == room.widgets.length) { if (index == room.widgets.length) {
return ListTile( return ListTile(
title: Text(L10n.of(context)!.integrationsNotImplemented), leading: const Icon(Icons.edit),
leading: const Icon(Icons.info), title: Text(L10n.of(context)!.editWidgets),
onTap: () {
Navigator.of(context).pop();
showDialog(
context: context,
builder: (context) => EditWidgetsDialog(room: room),
);
},
); );
} }
final widget = room.widgets[index]; final widget = room.widgets[index];

View File

@ -12,6 +12,7 @@ import 'package:matrix/matrix.dart';
import 'package:vrouter/vrouter.dart'; import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/chat/cupertino_widgets_bottom_sheet.dart'; import 'package:fluffychat/pages/chat/cupertino_widgets_bottom_sheet.dart';
import 'package:fluffychat/pages/chat/edit_widgets_dialog.dart';
import 'package:fluffychat/pages/chat/widgets_bottom_sheet.dart'; import 'package:fluffychat/pages/chat/widgets_bottom_sheet.dart';
import 'matrix.dart'; import 'matrix.dart';
@ -46,17 +47,16 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
(u) => setState(() {}), (u) => setState(() {}),
); );
final items = <PopupMenuEntry<String>>[ final items = <PopupMenuEntry<String>>[
if (widget.room.widgets.isNotEmpty) PopupMenuItem<String>(
PopupMenuItem<String>( value: 'widgets',
value: 'widgets', child: Row(
child: Row( children: [
children: [ const Icon(Icons.widgets_outlined),
const Icon(Icons.widgets_outlined), const SizedBox(width: 12),
const SizedBox(width: 12), Text(L10n.of(context)!.matrixWidgets),
Text(L10n.of(context)!.matrixWidgets), ],
],
),
), ),
),
widget.room.pushRuleState == PushRuleState.notify widget.room.pushRuleState == PushRuleState.notify
? PopupMenuItem<String>( ? PopupMenuItem<String>(
value: 'mute', value: 'mute',
@ -129,7 +129,14 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
onSelected: (String choice) async { onSelected: (String choice) async {
switch (choice) { switch (choice) {
case 'widgets': case 'widgets':
_showWidgets(); if (widget.room.widgets.isNotEmpty) {
_showWidgets();
} else {
showDialog(
context: context,
builder: (context) => EditWidgetsDialog(room: widget.room),
);
}
break; break;
case 'leave': case 'leave':
final confirmed = await showOkCancelAlertDialog( final confirmed = await showOkCancelAlertDialog(

View File

@ -990,7 +990,7 @@ packages:
name: matrix name: matrix
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.13" version: "0.8.14"
matrix_api_lite: matrix_api_lite:
dependency: transitive dependency: transitive
description: description:

View File

@ -58,7 +58,7 @@ dependencies:
keyboard_shortcuts: ^0.1.4 keyboard_shortcuts: ^0.1.4
localstorage: ^4.0.0+1 localstorage: ^4.0.0+1
lottie: ^1.2.2 lottie: ^1.2.2
matrix: ^0.8.13 matrix: ^0.8.14
matrix_link_text: ^1.0.2 matrix_link_text: ^1.0.2
open_noti_settings: ^0.4.0 open_noti_settings: ^0.4.0
package_info_plus: ^1.3.0 package_info_plus: ^1.3.0