import 'package:flutter/material.dart'; import 'package:localstore/localstore.dart'; import 'package:outbag_app/tools/assets.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class RoomVisibility { final int type; const RoomVisibility(this.type); static RoomVisibility get private { return const RoomVisibility(0); } static RoomVisibility get local { return const RoomVisibility(1); } static RoomVisibility get public { return const RoomVisibility(2); } IconData get icon { if (type == 2) { return Icons.public; } else if (type == 1) { return Icons.home; } return Icons.lock; } String text(BuildContext context) { final trans = AppLocalizations.of(context); if (type == 2) { return trans!.roomVisibilityGlobal; } else if (type == 1) { return trans!.roomVisibilityLocal; } return trans!.roomVisibilityPrivate; } static List list() { return [ RoomVisibility.private, RoomVisibility.local, RoomVisibility.public, ]; } } class RoomIcon { final String type; RoomIcon({required this.type}); static RoomIcon get love { return RoomIcon(type: "Love"); } static RoomIcon get sports { return RoomIcon(type: "Sports"); } static RoomIcon get pets { return RoomIcon(type: "Pets"); } static RoomIcon get vacation { return RoomIcon(type: "Vacation"); } static RoomIcon get gifts { return RoomIcon(type: "Gifts"); } static RoomIcon get groceries { return RoomIcon(type: "Groceries"); } static RoomIcon get fashion { return RoomIcon(type: "Fashion"); } static RoomIcon get art { return RoomIcon(type: "Art"); } static RoomIcon get tech { return RoomIcon(type: "Tech"); } static RoomIcon get home { return RoomIcon(type: "Home"); } static RoomIcon get family { return RoomIcon(type: "Family"); } static RoomIcon get social { return RoomIcon(type: "Social"); } static RoomIcon get other { return RoomIcon(type: "Other"); } static List list() { return [ RoomIcon.love, RoomIcon.sports, RoomIcon.pets, RoomIcon.vacation, RoomIcon.gifts, RoomIcon.groceries, RoomIcon.fashion, RoomIcon.art, RoomIcon.tech, RoomIcon.home, RoomIcon.family, RoomIcon.social, RoomIcon.other, ]; } String get text { switch (type.toLowerCase()) { case 'love': return 'Friends'; case 'sports': return 'Sports'; case 'pets': return 'Pets'; case 'vacation': return 'Vacation'; case 'gifts': return 'Gifts'; case 'groceries': return 'Groceries'; case 'fashion': return 'Clothing'; case 'art': return 'Arts & Crafts'; case 'tech': return 'Electronics'; case 'home': return 'Home supplies'; case 'family': return 'Family'; case 'social': return 'Social'; case 'other': default: return 'Other'; } } // return image name String get img { String path = ""; switch (type.toLowerCase()) { case 'love': path = 'undraw/undraw_couple.svg'; break; case 'sports': path = 'undraw/undraw_greek_freak.svg'; break; case 'pets': path = 'undraw/undraw_dog.svg'; break; case 'vacation': path = 'undraw/undraw_trip.svg'; break; case 'gifts': path = 'undraw/undraw_gifts.svg'; break; case 'groceries': path = 'undraw/undraw_gone_shopping.svg'; break; case 'fashion': path = 'undraw/undraw_jewelry.svg'; break; case 'art': path = 'undraw/undraw_sculpting.svg'; break; case 'tech': path = 'undraw/undraw_progressive_app.svg'; break; case 'home': path = 'undraw/undraw_under_construction.svg'; break; case 'family': path = 'undraw/undraw_family.svg'; break; case 'social': path = 'undraw/undraw_pizza_sharing.svg'; break; case 'other': default: path = 'undraw/undraw_file_manager.svg'; } return asset(path); } } class Room { String id; String serverTag; String name; String description; RoomIcon? icon = RoomIcon.other; RoomVisibility? visibility = RoomVisibility.private; Room( {required this.id, required this.serverTag, this.name = "", this.description = "", this.icon, this.visibility}); @override bool operator ==(Object r) { if (r.runtimeType != runtimeType) { return false; } final me = humanReadable; final other = (r as Room).humanReadable; return me == other; } String get humanReadable { return '$id@$serverTag'; } // get list of all known rooms static Future> listRooms() async { final db = Localstore.instance; final rooms = (await db.collection('rooms').get())!; List builder = []; for (MapEntry entry in rooms.entries) { try { builder.add(Room.fromMap(entry.value)); } catch (e) { // skip invalid rooms // NOTE: might want to autodelete them in the future // although keeping them might be ok, // in case we ever get a new dataset to fix the current state } } return builder; } // listen to room change static listen(Function(Map) cb) async { final db = Localstore.instance; final stream = db.collection('rooms').stream; stream.listen(cb); } factory Room.fromMap(Map map) { return Room( id: map['id'], serverTag: map['server'], name: map['name'], description: map['description'] ?? '', icon: RoomIcon(type: map['icon'] ?? 'Other'), visibility: RoomVisibility(map['visibility'] ?? 0)); } Map toMap() { return { 'id': id, 'server': serverTag, 'description': description, 'name': name, 'icon': icon?.type, 'visibility': visibility?.type }; } factory Room.fromJSON(dynamic json) { return Room( id: json['name'], serverTag: json['server'], name: json['title'], description: json['description'], icon: RoomIcon(type: json['icon']), visibility: RoomVisibility(json['visibility'])); } Future toDisk() async { final db = Localstore.instance; await db.collection('rooms').doc('$id@$serverTag').set(toMap()); } Future removeDisk() async { final db = Localstore.instance; // NOTE: Because categories, products and entries // are supposed to be stored in the room object // (they are just not read by Room.fromDisk) // deleting the document from the collection // should also get rid of affiliated collections await db.collection('rooms').doc('$id@$serverTag').delete(); } static Future fromDisk( {required String id, required String serverTag}) async { final db = Localstore.instance; final raw = await db.collection('rooms').doc('$id@$serverTag').get(); return Room.fromMap(raw!); } } class ShoppingListItem {} class RoomMember { final String id; final String serverTag; final bool isAdmin; const RoomMember( {required this.id, required this.serverTag, required this.isAdmin}); factory RoomMember.fromJSON(dynamic json) { return RoomMember( id: json['name'], serverTag: json['server'], isAdmin: json['admin'] == 1); } String get humanReadableName { return '$id@$serverTag'; } } class RoomInfo { final String owner; final bool isAdmin; final bool isOwner; final int permissions; const RoomInfo( {required this.permissions, required this.owner, required this.isAdmin, required this.isOwner}); factory RoomInfo.fromJSON(dynamic json) { return RoomInfo( permissions: json['rights'], owner: json['owner'], isAdmin: json['isAdmin'], 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; } }