From 99f0ed355843c82481405774319079c55774b385 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 31 Mar 2023 21:52:14 +0200 Subject: [PATCH] Basic Categories Page layout Planned Flow (unimplemented): - create new category on /edit-category page using bottom-right fab - sort categories using the two-line hamburger-style menu on each item - click on a category to modify/delete it NOTE: maybe on a different screen or MBS? --- lib/backend/room.dart | 57 ++++++++++++++++++++-- lib/screens/room/pages/categories.dart | 66 +++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 4 deletions(-) diff --git a/lib/backend/room.dart b/lib/backend/room.dart index 64dfe0e..2842ec5 100644 --- a/lib/backend/room.dart +++ b/lib/backend/room.dart @@ -221,11 +221,15 @@ class Room { this.icon, this.visibility}); - int compareTo(Room r) { + @override + bool operator ==(Object r) { + if (r.runtimeType != runtimeType) { + return false; + } final me = humanReadable; - final other = r.humanReadable; + final other = (r as Room).humanReadable; - return me.compareTo(other); + return me == other; } String get humanReadable { @@ -353,3 +357,50 @@ class RoomInfo { isOwner: json['isOwner']); } } + +class RoomCategory { + final int id; + final String name; + final ColorSwatch color; + + const RoomCategory( + {required this.id, required this.name, required this.color}); + + factory RoomCategory.fromJSON(dynamic json) { + return RoomCategory( + id: json['id'], + name: json['title'], + color: colorFromString(json['color'])); + } +} + +ColorSwatch colorFromString(String text) { + switch (text.toLowerCase()) { + case 'red-acc': + return Colors.redAccent; + case 'green-acc': + return Colors.greenAccent; + case 'yellow-acc': + return Colors.yellowAccent; + case 'blue-acc': + return Colors.blueAccent; + case 'aqua-acc': + return Colors.tealAccent; + case 'purple-acc': + return Colors.purpleAccent; + + case 'red': + return Colors.red; + case 'green': + return Colors.green; + case 'yellow': + return Colors.yellow; + case 'blue': + return Colors.blue; + case 'aqua': + return Colors.teal; + case 'purple': + default: + return Colors.purple; + } +} diff --git a/lib/screens/room/pages/categories.dart b/lib/screens/room/pages/categories.dart index f89771a..7aa62ed 100644 --- a/lib/screens/room/pages/categories.dart +++ b/lib/screens/room/pages/categories.dart @@ -1,5 +1,10 @@ import 'package:flutter/material.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:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; class RoomCategoriesPage extends StatefulWidget { final RoomInfo? info; @@ -12,8 +17,67 @@ class RoomCategoriesPage extends StatefulWidget { } class _RoomCategoriesPageState extends State { + List list = []; + + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.addPostFrameCallback((_) { + fetchCategories(); + }); + } + + void fetchCategories() async { + final user = context.read(); + + // TODO: load cached rooms + + doNetworkRequest(ScaffoldMessenger.of(context), + req: () => postWithCreadentials( + credentials: user, + target: user.server, + path: 'getCategories', + body: {'room': widget.room?.id, 'server': widget.room?.serverTag}), + onOK: (json) { + final resp = json['data'] + .map((raw) => RoomCategory.fromJSON(raw)) + .toList(); + setState(() { + list = resp; + }); + }); + } + @override Widget build(BuildContext context) { - return const Text('Categories'); + return Scaffold( + body: ReorderableListView.builder( + itemBuilder: (context, index) { + final item = list[index]; + + return ListTile( + key: Key('cat-${item.id}'), + leading: Icon(Icons.square_rounded, color: item.color), + title: Text(item.name), + onTap: () { + // TODO show edit category popup + // NOTE: maybe use ModalBottomSheet + // and show delete button in there + }, + ); + }, + itemCount: list.length, + onReorder: (int start, int current) {}, + ), + floatingActionButton: FloatingActionButton.extended( + icon: const Icon(Icons.add), + label: Text(AppLocalizations.of(context)!.newCategoryShort), + tooltip: AppLocalizations.of(context)!.newCategoryLong, + onPressed: () { + // TODO show new category popup + }, + ), + ); } }