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 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(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); // 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; } // name may not be empty if (_ctrName.text.isEmpty) { showSimpleSnackbar(scaffMgr, text: trans!.errorNoRoomName, action: trans.ok); return; } 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: '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)), ); } }