import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:outbag_app/backend/errors.dart'; import 'package:outbag_app/backend/request.dart'; import 'package:outbag_app/backend/room.dart'; import 'package:outbag_app/backend/user.dart'; import 'package:routemaster/routemaster.dart'; import 'dart:math'; class NewRoomPage extends StatefulWidget { const NewRoomPage({super.key}); @override State createState() => _NewRoomPageState(); } class _NewRoomPageState extends State { final TextEditingController _ctrID = TextEditingController(); final TextEditingController _ctrName = TextEditingController(); final TextEditingController _ctrDescription = TextEditingController(); RoomVisibility _ctrVis = RoomVisibility.private; RoomIcon _ctrIcon = RoomIcon.other; bool showSpinner = false; @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('Loading', style: textTheme.titleLarge), ]))) : Scaffold( appBar: AppBar( title: const Text('New Room'), leading: IconButton( onPressed: () { // go back Routemaster.of(context).history.back(); }, icon: const Icon(Icons.arrow_back), tooltip: "Go back", ), ), body: Center( child: Flexible( 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: 'Change room icon', onPressed: () { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Choose a room Icon'), 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; }); Navigator.of( context) .pop(); })); }).toList())), )); }, ), Padding( padding: const EdgeInsets.all(8), child: TextField( controller: _ctrID, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration( prefixIcon: Icon(Icons.fact_check), labelText: 'Room ID', hintText: 'Unique room id', helperText: 'the room id and server tag allow the room to be identified', border: OutlineInputBorder(), ), ), ), Padding( padding: const EdgeInsets.all(8), child: TextField( controller: _ctrName, keyboardType: TextInputType.name, decoration: const InputDecoration( prefixIcon: Icon(Icons.badge), labelText: 'Room Name', hintText: 'Give your room a name', helperText: 'Easily identify a room with a human readable name', border: OutlineInputBorder(), ), ), ), Padding( padding: const EdgeInsets.all(8), child: TextField( controller: _ctrDescription, keyboardType: TextInputType.text, decoration: const InputDecoration( prefixIcon: Icon(Icons.dns), labelText: 'Room Description', hintText: 'Briefly describe your Room', helperText: 'Make it easier for other to know what this room is used for', border: OutlineInputBorder(), ), ), ), Text('Visibility', style: textTheme.labelLarge), Text('Specify who has access to your room', style: textTheme.bodySmall), SegmentedButton( showSelectedIcon: true, multiSelectionEnabled: false, emptySelectionAllowed: false, segments: RoomVisibility.list().map((vis) { return ButtonSegment( value: vis, label: Text(vis.text), 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 rmaster = Routemaster.of(context); // ID should be at least three characters long if (_ctrID.text.length < 3) { final snackBar = SnackBar( behavior: SnackBarBehavior.floating, content: Text(_ctrID.text.isEmpty ? 'Please specify a Room ID' : 'Room ID has to be at least three characters long'), action: SnackBarAction( label: 'Ok', onPressed: () { scaffMgr.hideCurrentSnackBar(); }, ), ); scaffMgr.hideCurrentSnackBar(); scaffMgr.showSnackBar(snackBar); return; } // name may not be empty if (_ctrName.text.isEmpty) { final snackBar = SnackBar( behavior: SnackBarBehavior.floating, content: const Text('Please specify a room name'), action: SnackBarAction( label: 'Ok', onPressed: () { scaffMgr.hideCurrentSnackBar(); }, ), ); scaffMgr.hideCurrentSnackBar(); scaffMgr.showSnackBar(snackBar); return; } User user; try { user = await User.fromDisk(); } catch (_) { // user data invalid // shouldn't happen return; } final room = Room( id: _ctrID.text, serverTag: user.server.tag, name: _ctrName.text, description: _ctrDescription.text, icon: _ctrIcon, visibility: _ctrVis); try { final resp = await postWithCreadentials( target: user.server, credentials: user, path: 'createRoom', body: { 'room': room.id, 'server': room.serverTag, 'title': room.name, 'description': room.description, 'icon': room.icon?.type, 'visibility': room.visibility?.type } ); if (resp.res == Result.ok) { // room was created // save room await room.toDisk(); // move to home page rmaster.replace('/'); } else { // error final snackBar = SnackBar( behavior: SnackBarBehavior.floating, content: Text(errorAsString(resp.body)), action: SnackBarAction( label: 'Dismiss', onPressed: () { scaffMgr.hideCurrentSnackBar(); }, ), ); scaffMgr.hideCurrentSnackBar(); scaffMgr.showSnackBar(snackBar); } } catch (_) { final snackBar = SnackBar( behavior: SnackBarBehavior.floating, content: const Text('Network error'), action: SnackBarAction( label: 'Dismiss', onPressed: () { scaffMgr.hideCurrentSnackBar(); }, ), ); scaffMgr.hideCurrentSnackBar(); scaffMgr.showSnackBar(snackBar); } }, label: const Text('Create'), icon: const Icon(Icons.add)), ); } }