From 8706122590fe0e07547495b056c4bd2122046868 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Sun, 2 Apr 2023 13:14:58 +0200 Subject: [PATCH] Merged EditRoom and NewRoom page and moved ChangeRoomIcon-Dialog into seperate file. This was done in an attempt to remove redundancy --- lib/components/room_icon_picker.dart | 50 +++ lib/main.dart | 10 +- lib/screens/room/about/edit.dart | 299 ---------------- lib/screens/room/new.dart | 503 ++++++++++++++++----------- 4 files changed, 347 insertions(+), 515 deletions(-) create mode 100644 lib/components/room_icon_picker.dart delete mode 100644 lib/screens/room/about/edit.dart diff --git a/lib/components/room_icon_picker.dart b/lib/components/room_icon_picker.dart new file mode 100644 index 0000000..e523189 --- /dev/null +++ b/lib/components/room_icon_picker.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:outbag_app/backend/room.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'dart:math'; + +class RoomIconPicker extends StatelessWidget { + Function(RoomIcon)? onSelect; + RoomIconPicker({this.onSelect}); + + @override + Widget build(BuildContext context) { + double width = MediaQuery.of(context).size.width; + double height = MediaQuery.of(context).size.height; + double smallest = min(min(width, height), 400); + + return AlertDialog( + title: Text(AppLocalizations.of(context)!.chooseRoomIcon), + actions: const [], + content: SizedBox( + width: smallest * 0.3 * 3, + height: smallest * 0.3 * 3, + child: GridView.count( + crossAxisCount: 3, + children: RoomIcon.list().map((icon) { + return GridTile( + child: IconButton( + icon: SvgPicture.asset( + icon.img, + width: smallest * 0.3, + height: smallest * 0.3, + ), + // do not display tooltip for now + // as it is hard to translate + // and the tooltip prevented the click event, + // when clicked on the tooltip bar + // tooltip:icon.text, + onPressed: () { + if (onSelect != null) { + onSelect!(icon); + } + } + ) + ); + }).toList() + ) + ) + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 09b755e..a5727a3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,7 +15,6 @@ import 'package:outbag_app/screens/auth.dart'; import 'package:outbag_app/screens/room/new.dart'; import 'package:outbag_app/screens/room/join.dart'; import 'package:outbag_app/screens/room/main.dart'; -import 'package:outbag_app/screens/room/about/edit.dart'; import 'package:outbag_app/screens/room/about/members.dart'; import 'package:outbag_app/screens/room/about/permissions.dart'; import 'package:outbag_app/screens/settings/main.dart'; @@ -218,8 +217,7 @@ class _OutbagAppState extends State { GoRoute( path: 'new', name: 'new-room', - builder: (context, state) => - const NewRoomPage()), + builder: (context, state) => NewRoomPage()), ]), GoRoute( name: 'room', @@ -231,9 +229,9 @@ class _OutbagAppState extends State { GoRoute( name: 'edit-room', path: 'edit', - builder: (context, state) => EditRoomPage( - state.params['server'] ?? '', - state.params['id'] ?? '')), + builder: (context, state) => NewRoomPage( + server: state.params['server'] ?? '', + tag: state.params['id'] ?? '')), GoRoute( name: 'room-members', path: 'members', diff --git a/lib/screens/room/about/edit.dart b/lib/screens/room/about/edit.dart deleted file mode 100644 index 11c74c4..0000000 --- a/lib/screens/room/about/edit.dart +++ /dev/null @@ -1,299 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:go_router/go_router.dart'; -import 'package:outbag_app/backend/request.dart'; -import 'package:outbag_app/backend/room.dart'; -import 'package:outbag_app/backend/user.dart'; -import 'package:outbag_app/tools/fetch_wrapper.dart'; -import 'package:outbag_app/tools/snackbar.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'dart:math'; - -class EditRoomPage extends StatefulWidget { - final String server; - final String tag; - - const EditRoomPage(this.server, this.tag, {super.key}); - - @override - State createState() => _EditRoomPageState(); -} - -class _EditRoomPageState extends State { - final TextEditingController _ctrName = TextEditingController(); - final TextEditingController _ctrID = TextEditingController(); - final TextEditingController _ctrDescription = TextEditingController(); - RoomIcon _ctrIcon = RoomIcon.other; - Room? room; - - // show spinner by default - // until data has been fetched - bool showSpinner = true; - - void initFromRoom(Room room) { - _ctrID.text = room.id; - _ctrName.text = room.name; - _ctrDescription.text = room.description; - _ctrIcon = room.icon!; - - setState(() { - this.room = room; - }); - } - - // fetch room information - void fetchInfo() { - final sm = ScaffoldMessenger.of(context); - final router = GoRouter.of(context); - final user = context.read(); - - doNetworkRequest( - sm, - req: () => postWithCreadentials( - path: 'getRoomInfo', - credentials: user, - target: user.server, - body: {'room': widget.tag, 'server': widget.server}), - onOK: (body) async { - final room = Room.fromJSON(body['data']); - room.toDisk(); - }, - onNetworkErr: () { - // no room data available - // use data from disk - (() async { - try { - final diskRoom = - await Room.fromDisk(serverTag: widget.server, id: widget.tag); - initFromRoom(diskRoom); - } catch (_) { - // no room data available - // close screen - router.pushReplacementNamed('home'); - } - })(); - return true; - }, - onServerErr: (json) { - // user not allowed to be here - // close screen - router.pushReplacementNamed('home'); - return true; - }, - ); - } - - @override - void initState() { - super.initState(); - - Room.listen((_) async { - // rooms changed on disk - // probably this one, - // because it is currently open - // NOTE: might be a different room - // (if a background listener is implemented at some point, - // checking if this room changed might improve performance) - try { - final room = - await Room.fromDisk(serverTag: widget.server, id: widget.tag); - - initFromRoom(room); - - setState(() { - showSpinner = false; - }); - } catch (_) {} - }); - - WidgetsBinding.instance.addPostFrameCallback((_) => fetchInfo()); - } - - @override - Widget build(BuildContext context) { - final textTheme = Theme.of(context) - .textTheme - .apply(displayColor: Theme.of(context).colorScheme.onSurface); - - double width = MediaQuery.of(context).size.width; - double height = MediaQuery.of(context).size.height; - double smallest = min(min(width, height), 400); - - return showSpinner - ? Scaffold( - body: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const CircularProgressIndicator(), - Text(AppLocalizations.of(context)!.loading, style: textTheme.titleLarge), - ]))) - : Scaffold( - appBar: AppBar( - title: Text(AppLocalizations.of(context)!.editRoomMetadataShort), - ), - body: SingleChildScrollView( - child: Center( - child: Padding( - padding: const EdgeInsets.all(14), - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 400), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - IconButton( - icon: SvgPicture.asset( - _ctrIcon.img, - width: smallest * 0.3, - height: smallest * 0.3, - ), - tooltip: AppLocalizations.of(context)!.changeRoomIcon, - onPressed: () { - showDialog( - context: context, - builder: (ctx) => AlertDialog( - title: Text( - AppLocalizations.of(context)!.chooseRoomIcon), - actions: const [], - content: SizedBox( - width: smallest * 0.3 * 3, - height: smallest * 0.3 * 3, - child: GridView.count( - crossAxisCount: 3, - children: RoomIcon.list() - .map((icon) { - return GridTile( - child: IconButton( - icon: SvgPicture - .asset( - icon.img, - width: - smallest * - 0.3, - height: - smallest * - 0.3, - ), - tooltip: - icon.text, - onPressed: () { - setState(() { - _ctrIcon = - icon; - }); - context.pop(); - })); - }).toList())), - )); - }, - ), - Padding( - padding: const EdgeInsets.all(8), - child: TextField( - enabled: false, - controller: _ctrID, - keyboardType: TextInputType.emailAddress, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.fact_check), - labelText: AppLocalizations.of(context)! - .inputRoomIdLabel, - hintText: AppLocalizations.of(context)! - .inputRoomIdHint, - helperText: AppLocalizations.of(context)! - .inputRoomIdHelp, - border: const OutlineInputBorder(), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(8), - child: TextField( - controller: _ctrName, - keyboardType: TextInputType.name, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.badge), - labelText: AppLocalizations.of(context)! - .inputRoomNameLabel, - hintText: AppLocalizations.of(context)! - .inputRoomNameHint, - helperText: AppLocalizations.of(context)! - .inputRoomNameHelp, - border: const OutlineInputBorder(), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(8), - child: TextField( - controller: _ctrDescription, - keyboardType: TextInputType.text, - decoration: InputDecoration( - labelText: AppLocalizations.of(context)! - .inputRoomDescriptionLabel, - hintText: AppLocalizations.of(context)! - .inputRoomDescriptionHint, - helperText: AppLocalizations.of(context)! - .inputRoomDescriptionHelp, - prefixIcon: const Icon(Icons.dns), - border: const OutlineInputBorder(), - ), - ), - ), - ], - ))))), - floatingActionButton: FloatingActionButton.extended( - onPressed: () async { - final scaffMgr = ScaffoldMessenger.of(context); - final nav = Navigator.of(context); - final trans = AppLocalizations.of(context); - - // name may not be empty - if (_ctrName.text.isEmpty) { - showSimpleSnackbar(scaffMgr, - text: trans!.errorNoRoomName, action: trans.ok); - - return; - } - - User user; - try { - user = await User.fromDisk(); - } catch (_) { - // user data invalid - // shouldn't happen - return; - } - - Room clone = room!; - clone.name = _ctrName.text; - clone.description = _ctrDescription.text; - clone.icon = _ctrIcon; - - doNetworkRequest(scaffMgr, - req: ()=>postWithCreadentials( - target: user.server, - credentials: user, - path: 'changeRoomMeta', - body: { - 'room': clone.id, - 'server': clone.serverTag, - 'title': clone.name, - 'description': clone.description, - 'icon': clone.icon?.type, - }), - onOK: (_) async { - // room was created - // save room - await clone.toDisk(); - nav.pop(); - } - ); - }, - label: Text(AppLocalizations.of(context)!.update), - icon: const Icon(Icons.edit)), - ); - } -} diff --git a/lib/screens/room/new.dart b/lib/screens/room/new.dart index a5ec3d3..aa22288 100644 --- a/lib/screens/room/new.dart +++ b/lib/screens/room/new.dart @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart'; import 'package:outbag_app/backend/request.dart'; import 'package:outbag_app/backend/room.dart'; import 'package:outbag_app/backend/user.dart'; +import 'package:outbag_app/components/room_icon_picker.dart'; import 'package:outbag_app/tools/fetch_wrapper.dart'; import 'package:outbag_app/tools/snackbar.dart'; import 'package:provider/provider.dart'; @@ -11,243 +12,325 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'dart:math'; class NewRoomPage extends StatefulWidget { - const NewRoomPage({super.key}); + String? server; + String? tag; + NewRoomPage({this.server, this.tag, super.key}); @override State createState() => _NewRoomPageState(); } -class _NewRoomPageState extends State { +class _NewRoomPageState extends State { final TextEditingController _ctrID = TextEditingController(); final TextEditingController _ctrName = TextEditingController(); final TextEditingController _ctrDescription = TextEditingController(); RoomVisibility _ctrVis = RoomVisibility.private; RoomIcon _ctrIcon = RoomIcon.other; + Room? room; + bool showSpinner = false; + void initFromRoom(Room room) { + _ctrID.text = room.id; + _ctrName.text = room.name; + _ctrDescription.text = room.description; + _ctrIcon = room.icon!; + + setState(() { + this.room = room; + }); + } + + // fetch room information + void fetchInfo() async { + final sm = ScaffoldMessenger.of(context); + final router = GoRouter.of(context); + final user = context.read(); + + try { + final diskRoom = + await Room.fromDisk(serverTag: widget.server!, id: widget.tag!); + initFromRoom(diskRoom); + } catch (_) {} + + doNetworkRequest( + sm, + req: () => postWithCreadentials( + path: 'getRoomInfo', + credentials: user, + target: user.server, + body: {'room': widget.tag, 'server': widget.server}), + onOK: (body) async { + final room = Room.fromJSON(body['data']); + room.toDisk(); + initFromRoom(room); + }, + onNetworkErr: () { + // no room data available + // use data from disk + (() async { + // no room data available + // close screen + router.pushReplacementNamed('home'); + })(); + return true; + }, + onServerErr: (json) { + // user not allowed to be here + // close screen + router.pushReplacementNamed('home'); + return true; + }, + ); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (isEditPage()) { + fetchInfo(); + } + }); + } + + bool isEditPage() { + return widget.server != null && widget.tag != null; + } + @override Widget build(BuildContext context) { final textTheme = Theme.of(context) - .textTheme - .apply(displayColor: Theme.of(context).colorScheme.onSurface); + .textTheme + .apply(displayColor: Theme.of(context).colorScheme.onSurface); double width = MediaQuery.of(context).size.width; double height = MediaQuery.of(context).size.height; double smallest = min(min(width, height), 400); return showSpinner - ? Scaffold( - body: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const CircularProgressIndicator(), - Text(AppLocalizations.of(context)!.loading, - style: textTheme.titleLarge), - ]))) - : Scaffold( - appBar: AppBar( - title: Text(AppLocalizations.of(context)!.newRoom), - ), - body: SingleChildScrollView( - child: Center( - child: Padding( - padding: const EdgeInsets.all(14), - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 400), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - IconButton( - icon: SvgPicture.asset( - _ctrIcon.img, - width: smallest * 0.3, - height: smallest * 0.3, - ), - tooltip: AppLocalizations.of(context)! - .changeRoomIcon, - onPressed: () { - showDialog( - context: context, - builder: (ctx) => AlertDialog( - title: Text( - AppLocalizations.of(context)! - .chooseRoomIcon), - actions: const [], - content: SizedBox( - width: smallest * 0.3 * 3, - height: smallest * 0.3 * 3, - child: GridView.count( - crossAxisCount: 3, - children: RoomIcon.list() - .map((icon) { - return GridTile( - child: IconButton( - icon: SvgPicture - .asset( - icon.img, - width: - smallest * - 0.3, - height: - smallest * - 0.3, - ), - // do not display tooltip for now - // as it is hard to translate - // and the tooltip prevented the click event, - // when clicked on the tooltip bar - // tooltip:icon.text, - onPressed: () { - setState(() { - _ctrIcon = - icon; - }); - Navigator.of(ctx) - .pop(); - })); - }).toList())), - )); - }, - ), - Padding( - padding: const EdgeInsets.all(8), - child: TextField( - controller: _ctrID, - keyboardType: TextInputType.emailAddress, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.fact_check), - labelText: AppLocalizations.of(context)! - .inputRoomIdLabel, - hintText: AppLocalizations.of(context)! - .inputRoomIdHint, - helperText: AppLocalizations.of(context)! - .inputRoomIdHelp, - border: const OutlineInputBorder(), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(8), - child: TextField( - controller: _ctrName, - keyboardType: TextInputType.name, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.badge), - labelText: AppLocalizations.of(context)! - .inputRoomNameLabel, - hintText: AppLocalizations.of(context)! - .inputRoomNameHint, - helperText: AppLocalizations.of(context)! - .inputRoomNameHelp, - border: const OutlineInputBorder(), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(8), - child: TextField( - controller: _ctrDescription, - keyboardType: TextInputType.text, - decoration: InputDecoration( - labelText: AppLocalizations.of(context)! - .inputRoomDescriptionLabel, - hintText: AppLocalizations.of(context)! - .inputRoomDescriptionHint, - helperText: AppLocalizations.of(context)! - .inputRoomDescriptionHelp, - prefixIcon: const Icon(Icons.dns), - border: const OutlineInputBorder(), - ), - ), - ), - Text( - AppLocalizations.of(context)! - .roomVisibilityTitle, - style: textTheme.labelLarge), - Text( - AppLocalizations.of(context)! - .roomVisibilitySubtitle, - style: textTheme.bodySmall), - SegmentedButton( - showSelectedIcon: true, - multiSelectionEnabled: false, - emptySelectionAllowed: false, - segments: RoomVisibility.list().map((vis) { - return ButtonSegment( - value: vis, - label: Text(vis.text(context)), - icon: Icon(vis.icon)); - }).toList(), - onSelectionChanged: ((vset) { - setState(() { - _ctrVis = vset.single; - }); - }), - selected: {_ctrVis}, - selectedIcon: Icon(_ctrVis.icon), - ), - ], - ))))), - floatingActionButton: FloatingActionButton.extended( - onPressed: () async { - final scaffMgr = ScaffoldMessenger.of(context); - final router = GoRouter.of(context); - final trans = AppLocalizations.of(context); + ? Scaffold( + body: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const CircularProgressIndicator(), + Text(AppLocalizations.of(context)!.loading, + style: textTheme.titleLarge), + ]))) + : Scaffold( + appBar: AppBar( + title: Text(isEditPage() + ? AppLocalizations.of(context)!.editRoomMetadata + : AppLocalizations.of(context)!.newRoom), + ), + body: SingleChildScrollView( + child: Center( + child: Padding( + padding: const EdgeInsets.all(14), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 400), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + IconButton( + icon: SvgPicture.asset( + _ctrIcon.img, + width: smallest * 0.3, + height: smallest * 0.3, + ), + tooltip: AppLocalizations.of(context)! + .changeRoomIcon, + onPressed: () { + showDialog( + context: context, + builder: (ctx) => + RoomIconPicker(onSelect: (icon) { + setState(() { + _ctrIcon = icon; + }); + context.pop(); + })); + }), + Padding( + padding: const EdgeInsets.all(8), + child: TextField( + enabled: !isEditPage(), + controller: _ctrID, + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration( + prefixIcon: const Icon(Icons.fact_check), + labelText: AppLocalizations.of(context)! + .inputRoomIdLabel, + hintText: AppLocalizations.of(context)! + .inputRoomIdHint, + helperText: AppLocalizations.of(context)! + .inputRoomIdHelp, + border: const OutlineInputBorder(), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8), + child: TextField( + controller: _ctrName, + keyboardType: TextInputType.name, + decoration: InputDecoration( + prefixIcon: const Icon(Icons.badge), + labelText: AppLocalizations.of(context)! + .inputRoomNameLabel, + hintText: AppLocalizations.of(context)! + .inputRoomNameHint, + helperText: AppLocalizations.of(context)! + .inputRoomNameHelp, + border: const OutlineInputBorder(), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8), + child: TextField( + controller: _ctrDescription, + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: AppLocalizations.of(context)! + .inputRoomDescriptionLabel, + hintText: AppLocalizations.of(context)! + .inputRoomDescriptionHint, + helperText: AppLocalizations.of(context)! + .inputRoomDescriptionHelp, + prefixIcon: const Icon(Icons.dns), + border: const OutlineInputBorder(), + ), + ), + ), + ...(!isEditPage()) + ? [ + Text( + AppLocalizations.of(context)! + .roomVisibilityTitle, + style: textTheme.labelLarge), + Text( + AppLocalizations.of(context)! + .roomVisibilitySubtitle, + style: textTheme.bodySmall), + SegmentedButton( + showSelectedIcon: true, + multiSelectionEnabled: false, + emptySelectionAllowed: false, + segments: + RoomVisibility.list().map((vis) { + return ButtonSegment< + RoomVisibility>( + value: vis, + label: Text(vis.text(context)), + icon: Icon(vis.icon)); + }).toList(), + onSelectionChanged: ((vset) { + setState(() { + _ctrVis = vset.single; + }); + }), + selected: {_ctrVis}, + selectedIcon: Icon(_ctrVis.icon), + ), + ] + : [] + ], + ))))), + floatingActionButton: FloatingActionButton.extended( + onPressed: () async { + final scaffMgr = ScaffoldMessenger.of(context); + final router = GoRouter.of(context); + final trans = AppLocalizations.of(context); - // ID should be at least three characters long - if (_ctrID.text.length < 3) { - showSimpleSnackbar(scaffMgr, - text: _ctrID.text.isEmpty - ? trans!.errorNoRoomId - : trans!.errorRoomIdLength, - action: trans.ok); + // name may not be empty + if (_ctrName.text.isEmpty) { + showSimpleSnackbar(scaffMgr, + text: trans!.errorNoRoomName, action: trans.ok); - return; - } + return; + } - // name may not be empty - if (_ctrName.text.isEmpty) { - showSimpleSnackbar(scaffMgr, - text: trans!.errorNoRoomName, action: trans.ok); + final user = context.read(); - return; - } + if (isEditPage()) { + final nav = Navigator.of(context); + Room clone = room!; + clone.name = _ctrName.text; + clone.description = _ctrDescription.text; + clone.icon = _ctrIcon; - final user = context.read(); - final room = Room( - id: _ctrID.text, - serverTag: user.server.tag, - name: _ctrName.text, - description: _ctrDescription.text, - icon: _ctrIcon, - visibility: _ctrVis); + doNetworkRequest(scaffMgr, + req: () => postWithCreadentials( + target: user.server, + credentials: user, + path: 'changeRoomMeta', + body: { + 'room': clone.id, + 'server': clone.serverTag, + 'title': clone.name, + 'description': clone.description, + 'icon': clone.icon?.type, + }), + onOK: (_) async { + // room was created + // save room + await clone.toDisk(); + nav.pop(); + }); - doNetworkRequest(scaffMgr, - req: () => postWithCreadentials( - target: user.server, - credentials: user, - path: 'createRoom', - body: { - 'room': room.id, - 'title': room.name, - 'description': room.description, - 'icon': room.icon?.type, - 'visibility': room.visibility?.type - }), - onOK: (_) async { - // room was created - // save room - await room.toDisk(); - // move to home page - router.pushReplacementNamed('home'); - }); - }, - label: Text(AppLocalizations.of(context)!.createRoomShort), - icon: const Icon(Icons.add)), - ); + } else { + // new room specific tests & request + + // ID should be at least three characters long + if (_ctrID.text.length < 3) { + showSimpleSnackbar(scaffMgr, + text: _ctrID.text.isEmpty + ? trans!.errorNoRoomId + : trans!.errorRoomIdLength, + action: trans.ok); + + return; + } + + final room = Room( + id: _ctrID.text, + serverTag: user.server.tag, + name: _ctrName.text, + description: _ctrDescription.text, + icon: _ctrIcon, + visibility: _ctrVis); + + doNetworkRequest(scaffMgr, + req: () => postWithCreadentials( + target: user.server, + credentials: user, + path: 'createRoom', + body: { + 'room': room.id, + 'title': room.name, + 'description': room.description, + 'icon': room.icon?.type, + 'visibility': room.visibility?.type + }), + onOK: (_) async { + // room was created + // save room + await room.toDisk(); + // move to home page + router.pushReplacementNamed('home'); + }); + } + + }, + label: Text(isEditPage() + ? AppLocalizations.of(context)!.editRoomMetadataShort + : AppLocalizations.of(context)!.createRoomShort), + icon: Icon(isEditPage() ? Icons.edit : Icons.add)), + ); } }