actions-test/lib/screens/room/join.dart

308 lines
13 KiB
Dart
Raw Normal View History

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:outbag_app/tools/fetch_wrapper.dart';
import 'package:routemaster/routemaster.dart';
import 'dart:math';
class JoinRoomPage extends StatefulWidget {
const JoinRoomPage({super.key});
@override
State<StatefulWidget> createState() => _JoinRoomPageState();
}
class _JoinRoomPageState extends State {
List<Room> rooms = [];
@override
void didChangeDependencies() {
super.didChangeDependencies();
final sm = ScaffoldMessenger.of(context);
doNetworkRequest(null,
req: (user) => postWithCreadentials(
path: 'listPublicRooms',
credentials: user!,
target: user.server,
body: {}),
onOK: (body) async {
// parse rooms
final list = body['data'];
// try to fetch a list of rooms the user is a member of
// use an empty blacklist when request is not successful
final List<Room> blacklist = [];
doNetworkRequest(sm,
req: (user) => postWithCreadentials(
path: 'listRooms',
credentials: user!,
target: user.server,
body: {}),
onOK: (body) {
final List<Room> list = body['data'].map<Room>((json) {
return Room.fromJSON(json);
}).toList();
for (Room r in list) {
blacklist.add(r);
}
});
// process the list of public rooms
final List<Room> builder = [];
processor:
for (dynamic raw in list) {
try {
final room = Room.fromJSON(raw);
// figure out if room is on blacklist
// only add room to list,
// if not on blacklist
for (Room r in blacklist) {
if (r.compareTo(room) == 0) {
// server on white list
// move to next iteration on outer for loop
continue processor;
}
}
builder.add(room);
} catch (_) {
// ignore room
}
}
setState(() {
rooms = builder;
});
});
}
@override
void initState() {
super.initState();
}
@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(width, height);
return Scaffold(
appBar: AppBar(
title: const Text('Join Room'),
leading: IconButton(
onPressed: () {
// go back
Routemaster.of(context).history.back();
},
icon: const Icon(Icons.arrow_back),
tooltip: "Go back",
),
actions: [
IconButton(
icon: const Icon(Icons.search),
tooltip: "Search",
onPressed: () {
// show searchbar
// NOTE: location currently unknown
},
),
IconButton(
icon: const Icon(Icons.refresh),
tooltip: "Refresh",
onPressed: () {
// fetch public rooms again
didChangeDependencies();
},
),
MenuAnchor(
builder: (ctx, controller, child) {
return IconButton(
onPressed: () {
if (controller.isOpen) {
controller.close();
} else {
controller.open();
}
},
icon: const Icon(Icons.more_vert),
);
},
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.drafts),
child: const Text('Join invite-only room'),
onPressed: () {
// show settings screen
Routemaster.of(context).push("/add-room/by-id");
}),
])
],
),
body: rooms.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('No new Rooms found', style: textTheme.titleLarge),
],
))
: ListView.builder(
itemCount: rooms.length,
itemBuilder: (ctx, i) {
final room = rooms[i];
return Card(
margin: const EdgeInsets.all(8.0),
clipBehavior: Clip.antiAliasWithSaveLayer,
semanticContainer: true,
child: InkWell(
onTap: () {
// TODO: show modalBottomSheet
// with room information
// and join button
showModalBottomSheet(
context: ctx,
builder: (ctx) {
return BottomSheet(
onClosing: () {},
builder: (ctx) {
return Column(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(14),
child: Column(children: [
// room icon
SvgPicture.asset(
(room.icon?.img)!,
width: smallest * 0.2,
height: smallest * 0.2,
),
// room name
Text(
room.name,
style: textTheme.displayMedium,
),
Text(
'${room.id}@${room.serverTag}',
style: textTheme.labelSmall,
),
// description
Text(room.description,
style: textTheme.bodyLarge),
// visibility
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(room.visibility?.icon),
Text((room
.visibility?.text)!),
]),
])),
// action buttons
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
// cancel button
Padding(
padding:
const EdgeInsets.all(14),
child: ElevatedButton.icon(
icon:
const Icon(Icons.close),
label: const Text('Cancel'),
onPressed: () {
// close sheet
Navigator.pop(context);
},
)),
// join room button
Padding(
padding:
const EdgeInsets.all(14),
child: FilledButton.icon(
icon:
const Icon(Icons.check),
label: const Text('Join'),
onPressed: () async {
final scaffMgr =
ScaffoldMessenger.of(
context);
final rmaster =
Routemaster.of(
context);
final nav =
Navigator.of(context);
doNetworkRequest(scaffMgr,
req: (user) =>
postWithCreadentials(
credentials:
user!,
target: user
.server,
path:
'joinPublicRoom',
body: {
'room':
room.id,
'server': room
.serverTag
}),
onOK: (body) async {
await room.toDisk();
nav.pop();
rmaster.replace(
'/r/${room.serverTag}/${room.id}');
});
},
))
])
],
);
},
);
});
},
child: Container(
padding: const EdgeInsets.fromLTRB(10, 5, 5, 10),
child: ListTile(
title: Text(room.name),
visualDensity: const VisualDensity(vertical: 3),
subtitle: Text(room.description),
leading: AspectRatio(
aspectRatio: 1 / 1,
child: SvgPicture.asset("${room.icon?.img}"),
),
hoverColor: Colors.transparent,
))));
},
),
floatingActionButton: FloatingActionButton.extended(
label: const Text('New'),
icon: const Icon(Icons.add),
onPressed: () {
// create new room
Routemaster.of(context).push("/add-room/new");
},
tooltip: 'Create Room',
),
);
}
}