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?
This commit is contained in:
Jakob Meier 2023-03-31 21:52:14 +02:00
parent cb232cf271
commit 99f0ed3558
No known key found for this signature in database
GPG key ID: 66BDC7E6A01A6152
2 changed files with 119 additions and 4 deletions

View file

@ -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<int> 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<int> 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;
}
}

View file

@ -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<RoomCategoriesPage> {
List<RoomCategory> list = [];
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
fetchCategories();
});
}
void fetchCategories() async {
final user = context.read<User>();
// 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<RoomCategory>((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
},
),
);
}
}