diff --git a/lib/generated/grpc/party_room_server/index.pb.dart b/lib/generated/grpc/party_room_server/index.pb.dart index fb5ea57..312e260 100644 --- a/lib/generated/grpc/party_room_server/index.pb.dart +++ b/lib/generated/grpc/party_room_server/index.pb.dart @@ -518,6 +518,7 @@ class RoomData extends $pb.GeneratedMessage { RoomStatus? status, $core.String? deviceUUID, $core.String? announcement, + $core.String? avatar, }) { final $result = create(); if (id != null) { @@ -550,6 +551,9 @@ class RoomData extends $pb.GeneratedMessage { if (announcement != null) { $result.announcement = announcement; } + if (avatar != null) { + $result.avatar = avatar; + } return $result; } RoomData._() : super(); @@ -567,6 +571,7 @@ class RoomData extends $pb.GeneratedMessage { ..e(8, _omitFieldNames ? '' : 'status', $pb.PbFieldType.OE, defaultOrMaker: RoomStatus.All, valueOf: RoomStatus.valueOf, enumValues: RoomStatus.values) ..aOS(9, _omitFieldNames ? '' : 'deviceUUID', protoName: 'deviceUUID') ..aOS(10, _omitFieldNames ? '' : 'announcement') + ..aOS(11, _omitFieldNames ? '' : 'avatar') ..hasRequiredFields = false ; @@ -674,6 +679,15 @@ class RoomData extends $pb.GeneratedMessage { $core.bool hasAnnouncement() => $_has(9); @$pb.TagNumber(10) void clearAnnouncement() => clearField(10); + + @$pb.TagNumber(11) + $core.String get avatar => $_getSZ(10); + @$pb.TagNumber(11) + set avatar($core.String v) { $_setString(10, v); } + @$pb.TagNumber(11) + $core.bool hasAvatar() => $_has(10); + @$pb.TagNumber(11) + void clearAvatar() => clearField(11); } class RoomListPageReqData extends $pb.GeneratedMessage { diff --git a/lib/generated/grpc/party_room_server/index.pbjson.dart b/lib/generated/grpc/party_room_server/index.pbjson.dart index 00e7b2d..98d2736 100644 --- a/lib/generated/grpc/party_room_server/index.pbjson.dart +++ b/lib/generated/grpc/party_room_server/index.pbjson.dart @@ -164,6 +164,7 @@ const RoomData$json = { {'1': 'status', '3': 8, '4': 1, '5': 14, '6': '.RoomStatus', '10': 'status'}, {'1': 'deviceUUID', '3': 9, '4': 1, '5': 9, '10': 'deviceUUID'}, {'1': 'announcement', '3': 10, '4': 1, '5': 9, '10': 'announcement'}, + {'1': 'avatar', '3': 11, '4': 1, '5': 9, '10': 'avatar'}, ], }; @@ -174,7 +175,8 @@ final $typed_data.Uint8List roomDataDescriptor = $convert.base64Decode( 'KAlSBW93bmVyEhwKCW1heFBsYXllchgFIAEoBVIJbWF4UGxheWVyEh4KCmNyZWF0ZVRpbWUYBi' 'ABKANSCmNyZWF0ZVRpbWUSHAoJY3VyUGxheWVyGAcgASgFUgljdXJQbGF5ZXISIwoGc3RhdHVz' 'GAggASgOMgsuUm9vbVN0YXR1c1IGc3RhdHVzEh4KCmRldmljZVVVSUQYCSABKAlSCmRldmljZV' - 'VVSUQSIgoMYW5ub3VuY2VtZW50GAogASgJUgxhbm5vdW5jZW1lbnQ='); + 'VVSUQSIgoMYW5ub3VuY2VtZW50GAogASgJUgxhbm5vdW5jZW1lbnQSFgoGYXZhdGFyGAsgASgJ' + 'UgZhdmF0YXI='); @$core.Deprecated('Use roomListPageReqDataDescriptor instead') const RoomListPageReqData$json = { diff --git a/lib/grpc/party_room_server.dart b/lib/grpc/party_room_server.dart index 8aca767..a5a22ce 100644 --- a/lib/grpc/party_room_server.dart +++ b/lib/grpc/party_room_server.dart @@ -31,7 +31,7 @@ class PartyRoomGrpcServer { return await _indexService.getRoomList(req); } - static Future createRoom(RoomData roomData) async { - await _indexService.createRoom(roomData); + static Future createRoom(RoomData roomData) async { + return await _indexService.createRoom(roomData); } } diff --git a/lib/ui/party_room/dialogs/party_room_create_dialog_ui.dart b/lib/ui/party_room/dialogs/party_room_create_dialog_ui.dart index 3cd56df..dcba1c8 100644 --- a/lib/ui/party_room/dialogs/party_room_create_dialog_ui.dart +++ b/lib/ui/party_room/dialogs/party_room_create_dialog_ui.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; +import 'dart:math'; + import 'package:flutter/services.dart'; import 'package:starcitizen_doctor/base/ui.dart'; import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pb.dart'; @@ -119,6 +122,15 @@ class PartyRoomCreateDialogUI extends BaseUI { ); } + Color generateColorFromSeed(String seed) { + int hash = utf8 + .encode(seed) + .fold(0, (previousValue, element) => 31 * previousValue + element); + Random random = Random(hash); + return Color.fromARGB( + 255, random.nextInt(256), random.nextInt(256), random.nextInt(256)); + } + List makeSubTypeSelectWidgets( BuildContext context, PartyRoomCreateDialogUIModel model) { bool isItemSelected(RoomSubtype subtype) { @@ -135,7 +147,7 @@ class PartyRoomCreateDialogUI extends BaseUI { Container( decoration: BoxDecoration( color: isItemSelected(item) - ? Colors.green + ? generateColorFromSeed(item.name).withOpacity(.4) : FluentTheme.of(context).cardColor, borderRadius: BorderRadius.circular(1000)), padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 12), diff --git a/lib/ui/party_room/dialogs/party_room_create_dialog_ui_model.dart b/lib/ui/party_room/dialogs/party_room_create_dialog_ui_model.dart index f1c71cd..bb779ad 100644 --- a/lib/ui/party_room/dialogs/party_room_create_dialog_ui_model.dart +++ b/lib/ui/party_room/dialogs/party_room_create_dialog_ui_model.dart @@ -67,6 +67,7 @@ class PartyRoomCreateDialogUIModel extends BaseUIModel { roomSubTypeIds: [for (var value in selectedSubType) value.id], owner: userName, deviceUUID: AppConf.deviceUUID, + maxPlayer: maxPlayer, announcement: announcementCtrl.text.trim()))); isWorking = false; notifyListeners(); diff --git a/lib/ui/party_room/party_room_home_ui.dart b/lib/ui/party_room/party_room_home_ui.dart index 6b7a5b4..3e18398 100644 --- a/lib/ui/party_room/party_room_home_ui.dart +++ b/lib/ui/party_room/party_room_home_ui.dart @@ -1,5 +1,12 @@ +import 'dart:convert'; +import 'dart:math'; +import 'dart:ui'; + +import 'package:extended_image/extended_image.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:starcitizen_doctor/base/ui.dart'; import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pb.dart'; +import 'package:starcitizen_doctor/widgets/cache_image.dart'; import 'party_room_home_ui_model.dart'; @@ -22,11 +29,163 @@ class PartyRoomHomeUI extends BaseUI { const Expanded( child: Center( child: Text("没有符合条件的房间!"), - )), + )) + else + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 24, right: 24), + child: AlignedGridView.count( + crossAxisCount: 3, + mainAxisSpacing: 24, + crossAxisSpacing: 24, + itemCount: model.rooms!.length, + itemBuilder: (context, index) { + final item = model.rooms![index]; + final itemType = model.roomTypes?[item.roomTypeID]; + final itemSubTypes = { + for (var t in itemType?.subTypes ?? []) t.id: t + }; + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(13), + image: DecorationImage( + image: ExtendedNetworkImageProvider(item.avatar, + cache: true), + fit: BoxFit.cover)), + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(.4), + borderRadius: BorderRadius.circular(13), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(13), + clipBehavior: Clip.hardEdge, + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: Padding( + padding: const EdgeInsets.only( + left: 16, right: 16, top: 12, bottom: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + "${itemType?.name ?? item.roomTypeID}房间", + style: const TextStyle(fontSize: 20), + ), + const SizedBox(width: 16), + Container( + padding: const EdgeInsets.only( + top: 3, + bottom: 3, + left: 12, + right: 12), + decoration: BoxDecoration( + color: Colors.green, + borderRadius: + BorderRadius.circular(1000)), + child: Text( + "${model.roomStatus[item.status]}")), + ], + ), + const SizedBox(height: 6), + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + makeItemRow("房主:", item.owner), + makeItemRow( + "当前人数:", "${item.curPlayer}"), + makeItemRow( + "最大人数:", "${item.maxPlayer}"), + ], + ), + ), + ClipRRect( + borderRadius: BorderRadius.circular(1000), + child: CacheNetImage( + url: item.avatar, + width: 64, + height: 64, + ), + ), + ], + ), + const SizedBox(height: 12), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + for (var value in item.roomSubTypeIds) + makeSubTypeTag( + value, model, itemSubTypes), + ], + ), + ) + ], + ), + ), + ), + ), + ), + ); + }, + ), + ), + ), ], ); } + Widget makeSubTypeTag(String id, PartyRoomHomeUIModel model, + Map itemSubTypes) { + final name = itemSubTypes[id]?.name ?? id; + final color = generateColorFromSeed(name).withOpacity(.6); + return Container( + padding: const EdgeInsets.only(left: 12, right: 12, top: 5, bottom: 5), + margin: const EdgeInsets.only(right: 6), + decoration: + BoxDecoration(color: color, borderRadius: BorderRadius.circular(12)), + child: Text( + name, + style: const TextStyle(fontSize: 13), + ), + ); + } + + Color generateColorFromSeed(String seed) { + int hash = utf8 + .encode(seed) + .fold(0, (previousValue, element) => 31 * previousValue + element); + Random random = Random(hash); + return Color.fromARGB( + 255, random.nextInt(256), random.nextInt(256), random.nextInt(256)); + } + + Widget makeItemRow(String title, String value) { + return Padding( + padding: const EdgeInsets.only(top: 1, bottom: 1), + child: Row( + children: [ + Text( + title, + style: TextStyle(color: Colors.white.withOpacity(.6)), + ), + const SizedBox(width: 12), + Expanded( + child: Text( + value, + ), + ), + ], + ), + ); + } + Widget makeHeader(BuildContext context, PartyRoomHomeUIModel model) { final subTypes = model.getCurRoomSubTypes(); return Container( @@ -95,7 +254,7 @@ class PartyRoomHomeUI extends BaseUI { onChanged: model.onChangeRoomSort)), const Spacer(), Button( - onPressed: () {}, + onPressed: model.onRefreshRoom, child: const Padding( padding: EdgeInsets.all(6), child: Icon(FluentIcons.refresh), diff --git a/lib/ui/party_room/party_room_home_ui_model.dart b/lib/ui/party_room/party_room_home_ui_model.dart index cc20e49..d080b00 100644 --- a/lib/ui/party_room/party_room_home_ui_model.dart +++ b/lib/ui/party_room/party_room_home_ui_model.dart @@ -68,8 +68,8 @@ class PartyRoomHomeUIModel extends BaseUIModel { final r = await handleError(() => PartyRoomGrpcServer.getRoomList( RoomListPageReqData( pageNum: Int64.tryParseInt("$pageNum"), - typeID: selectedRoomType?.id, - subTypeID: selectedRoomSubType?.id, + typeID: selectedRoomType?.id ?? "", + subTypeID: selectedRoomSubType?.id ?? "", status: selectedStatus))); if (r == null) return; if (r.pageData.hasNext) { @@ -115,7 +115,7 @@ class PartyRoomHomeUIModel extends BaseUIModel { types[element.id] = element; } if (types.isEmpty) return null; - final allSubType = RoomSubtype(id: "all", name: "全部"); + final allSubType = RoomSubtype(id: "", name: "全部"); selectedRoomSubType ??= allSubType; return {"all": allSubType}..addAll(types); } @@ -159,6 +159,12 @@ class PartyRoomHomeUIModel extends BaseUIModel { PartyRoomCreateDialogUIModel(Map.from(roomTypes!))); }, ); + if (room == null) return; dPrint(room); + reloadData(); + } + + onRefreshRoom() { + reloadData(); } }