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:
parent
cb232cf271
commit
99f0ed3558
2 changed files with 119 additions and 4 deletions
|
@ -221,11 +221,15 @@ class Room {
|
||||||
this.icon,
|
this.icon,
|
||||||
this.visibility});
|
this.visibility});
|
||||||
|
|
||||||
int compareTo(Room r) {
|
@override
|
||||||
|
bool operator ==(Object r) {
|
||||||
|
if (r.runtimeType != runtimeType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
final me = humanReadable;
|
final me = humanReadable;
|
||||||
final other = r.humanReadable;
|
final other = (r as Room).humanReadable;
|
||||||
|
|
||||||
return me.compareTo(other);
|
return me == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get humanReadable {
|
String get humanReadable {
|
||||||
|
@ -353,3 +357,50 @@ class RoomInfo {
|
||||||
isOwner: json['isOwner']);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:outbag_app/backend/request.dart';
|
||||||
import 'package:outbag_app/backend/room.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 {
|
class RoomCategoriesPage extends StatefulWidget {
|
||||||
final RoomInfo? info;
|
final RoomInfo? info;
|
||||||
|
@ -12,8 +17,67 @@ class RoomCategoriesPage extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RoomCategoriesPageState extends State<RoomCategoriesPage> {
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
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
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue