[Party Room] 创建房间

This commit is contained in:
xkeyC 2024-01-13 17:29:41 +08:00
parent 85f488c118
commit fbdfd61c09
12 changed files with 343 additions and 20 deletions

View File

@ -1,4 +1,5 @@
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grpc/grpc.dart';
import 'ui.dart'; import 'ui.dart';
@ -62,13 +63,11 @@ class BaseUIModel extends ChangeNotifier {
} catch (e) { } catch (e) {
dPrint("$runtimeType.handleError Error:$e"); dPrint("$runtimeType.handleError Error:$e");
String errorMsg = "Unknown Error"; String errorMsg = "Unknown Error";
// if (e is AppHttpResultData && stringIsNotEmpty(e.msg)) { if (e is GrpcError) {
// errorMsg = e.msg!; errorMsg = "服务器错误: ${e.message} ?? Unknown Error";
// return null; } else {
// } else {
// errorMsg = e.toString();
// }
errorMsg = e.toString(); errorMsg = e.toString();
}
if (showFullScreenError) { if (showFullScreenError) {
uiErrorMsg = errorMsg; uiErrorMsg = errorMsg;
notifyListeners(); notifyListeners();
@ -78,7 +77,8 @@ class BaseUIModel extends ChangeNotifier {
showToast(context!, errorOverride ?? errorMsg, showToast(context!, errorOverride ?? errorMsg,
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: MediaQuery.of(context!).size.width * .6, maxWidth: MediaQuery.of(context!).size.width * .6,
),title: "出现错误!"); ),
title: "出现错误!");
} }
} }
return null; return null;

View File

@ -47,6 +47,8 @@ class AppConf {
static const gameChannels = ["LIVE", "PTU", "EPTU"]; static const gameChannels = ["LIVE", "PTU", "EPTU"];
static String deviceUUID = "";
static late final String applicationSupportDir; static late final String applicationSupportDir;
static AppVersionData? networkVersionData; static AppVersionData? networkVersionData;
@ -83,6 +85,7 @@ class AppConf {
await box.put("install_id", const Uuid().v4()); await box.put("install_id", const Uuid().v4());
AnalyticsApi.touch("firstLaunch"); AnalyticsApi.touch("firstLaunch");
} }
deviceUUID = box.get("install_id", defaultValue: "");
} catch (e) { } catch (e) {
exit(1); exit(1);
} }

View File

View File

@ -517,6 +517,7 @@ class RoomData extends $pb.GeneratedMessage {
$core.int? curPlayer, $core.int? curPlayer,
RoomStatus? status, RoomStatus? status,
$core.String? deviceUUID, $core.String? deviceUUID,
$core.String? announcement,
}) { }) {
final $result = create(); final $result = create();
if (id != null) { if (id != null) {
@ -546,6 +547,9 @@ class RoomData extends $pb.GeneratedMessage {
if (deviceUUID != null) { if (deviceUUID != null) {
$result.deviceUUID = deviceUUID; $result.deviceUUID = deviceUUID;
} }
if (announcement != null) {
$result.announcement = announcement;
}
return $result; return $result;
} }
RoomData._() : super(); RoomData._() : super();
@ -562,6 +566,7 @@ class RoomData extends $pb.GeneratedMessage {
..a<$core.int>(7, _omitFieldNames ? '' : 'curPlayer', $pb.PbFieldType.O3, protoName: 'curPlayer') ..a<$core.int>(7, _omitFieldNames ? '' : 'curPlayer', $pb.PbFieldType.O3, protoName: 'curPlayer')
..e<RoomStatus>(8, _omitFieldNames ? '' : 'status', $pb.PbFieldType.OE, defaultOrMaker: RoomStatus.All, valueOf: RoomStatus.valueOf, enumValues: RoomStatus.values) ..e<RoomStatus>(8, _omitFieldNames ? '' : 'status', $pb.PbFieldType.OE, defaultOrMaker: RoomStatus.All, valueOf: RoomStatus.valueOf, enumValues: RoomStatus.values)
..aOS(9, _omitFieldNames ? '' : 'deviceUUID', protoName: 'deviceUUID') ..aOS(9, _omitFieldNames ? '' : 'deviceUUID', protoName: 'deviceUUID')
..aOS(10, _omitFieldNames ? '' : 'announcement')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -660,6 +665,15 @@ class RoomData extends $pb.GeneratedMessage {
$core.bool hasDeviceUUID() => $_has(8); $core.bool hasDeviceUUID() => $_has(8);
@$pb.TagNumber(9) @$pb.TagNumber(9)
void clearDeviceUUID() => clearField(9); void clearDeviceUUID() => clearField(9);
@$pb.TagNumber(10)
$core.String get announcement => $_getSZ(9);
@$pb.TagNumber(10)
set announcement($core.String v) { $_setString(9, v); }
@$pb.TagNumber(10)
$core.bool hasAnnouncement() => $_has(9);
@$pb.TagNumber(10)
void clearAnnouncement() => clearField(10);
} }
class RoomListPageReqData extends $pb.GeneratedMessage { class RoomListPageReqData extends $pb.GeneratedMessage {

View File

@ -163,6 +163,7 @@ const RoomData$json = {
{'1': 'curPlayer', '3': 7, '4': 1, '5': 5, '10': 'curPlayer'}, {'1': 'curPlayer', '3': 7, '4': 1, '5': 5, '10': 'curPlayer'},
{'1': 'status', '3': 8, '4': 1, '5': 14, '6': '.RoomStatus', '10': 'status'}, {'1': 'status', '3': 8, '4': 1, '5': 14, '6': '.RoomStatus', '10': 'status'},
{'1': 'deviceUUID', '3': 9, '4': 1, '5': 9, '10': 'deviceUUID'}, {'1': 'deviceUUID', '3': 9, '4': 1, '5': 9, '10': 'deviceUUID'},
{'1': 'announcement', '3': 10, '4': 1, '5': 9, '10': 'announcement'},
], ],
}; };
@ -173,7 +174,7 @@ final $typed_data.Uint8List roomDataDescriptor = $convert.base64Decode(
'KAlSBW93bmVyEhwKCW1heFBsYXllchgFIAEoBVIJbWF4UGxheWVyEh4KCmNyZWF0ZVRpbWUYBi' 'KAlSBW93bmVyEhwKCW1heFBsYXllchgFIAEoBVIJbWF4UGxheWVyEh4KCmNyZWF0ZVRpbWUYBi'
'ABKANSCmNyZWF0ZVRpbWUSHAoJY3VyUGxheWVyGAcgASgFUgljdXJQbGF5ZXISIwoGc3RhdHVz' 'ABKANSCmNyZWF0ZVRpbWUSHAoJY3VyUGxheWVyGAcgASgFUgljdXJQbGF5ZXISIwoGc3RhdHVz'
'GAggASgOMgsuUm9vbVN0YXR1c1IGc3RhdHVzEh4KCmRldmljZVVVSUQYCSABKAlSCmRldmljZV' 'GAggASgOMgsuUm9vbVN0YXR1c1IGc3RhdHVzEh4KCmRldmljZVVVSUQYCSABKAlSCmRldmljZV'
'VVSUQ='); 'VVSUQSIgoMYW5ub3VuY2VtZW50GAogASgJUgxhbm5vdW5jZW1lbnQ=');
@$core.Deprecated('Use roomListPageReqDataDescriptor instead') @$core.Deprecated('Use roomListPageReqDataDescriptor instead')
const RoomListPageReqData$json = { const RoomListPageReqData$json = {

View File

@ -16,6 +16,13 @@ final globalUIModelProvider = ChangeNotifierProvider((ref) => globalUIModel);
class AppGlobalUIModel extends BaseUIModel { class AppGlobalUIModel extends BaseUIModel {
Timer? activityThemeColorTimer; Timer? activityThemeColorTimer;
Future<String> getRunningGameUser() async {
await Future.delayed(const Duration(milliseconds: 300));
///TODO
return "xkeyC";
}
Future<bool> doCheckUpdate(BuildContext context, {bool init = true}) async { Future<bool> doCheckUpdate(BuildContext context, {bool init = true}) async {
dynamic checkUpdateError; dynamic checkUpdateError;
if (!init) { if (!init) {

View File

@ -30,4 +30,8 @@ class PartyRoomGrpcServer {
static Future<RoomListData> getRoomList(RoomListPageReqData req) async { static Future<RoomListData> getRoomList(RoomListPageReqData req) async {
return await _indexService.getRoomList(req); return await _indexService.getRoomList(req);
} }
static Future createRoom(RoomData roomData) async {
await _indexService.createRoom(roomData);
}
} }

View File

@ -0,0 +1,185 @@
import 'package:flutter/services.dart';
import 'package:starcitizen_doctor/base/ui.dart';
import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pb.dart';
import 'party_room_create_dialog_ui_model.dart';
class PartyRoomCreateDialogUI extends BaseUI<PartyRoomCreateDialogUIModel> {
@override
Widget? buildBody(BuildContext context, PartyRoomCreateDialogUIModel model) {
return ContentDialog(
title: makeTitle(context, model),
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .6),
content: Padding(
padding: const EdgeInsets.only(left: 12, right: 12, top: 12),
child: AnimatedSize(
duration: const Duration(milliseconds: 130),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (model.userName == null) ...[
SizedBox(
height: 200,
child: makeLoading(context),
)
] else ...[
Row(
children: [
const Text("请选择一种玩法"),
const SizedBox(width: 12),
Expanded(
child: SizedBox(
height: 36,
child: ComboBox<RoomType>(
value: model.selectedRoomType,
items: [
for (final t in model.roomTypes.entries)
ComboBoxItem(
value: t.value,
child: Text(t.value.name),
)
],
onChanged: model.onChangeRoomType)),
)
],
),
if (model.selectedRoomType != null &&
(model.selectedRoomType?.subTypes.isNotEmpty ?? false))
...makeSubTypeSelectWidgets(context, model),
const SizedBox(height: 24),
Row(
children: [
const Text("游戏用户名(自动获取)"),
const SizedBox(width: 12),
Expanded(
child: TextFormBox(
initialValue: model.userName,
enabled: false,
),
),
],
),
const SizedBox(height: 24),
Row(
children: [
const Text("最大玩家数2 ~ 32"),
const SizedBox(width: 12),
Expanded(
child: TextFormBox(
controller: model.playerMaxCtrl,
onChanged: (_) => model.notifyListeners(),
inputFormatters: [
FilteringTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
),
),
],
),
const SizedBox(height: 24),
const Text("公告(可选)"),
const SizedBox(height: 12),
TextFormBox(
controller: model.announcementCtrl,
maxLines: 5,
placeholder: "可编写 任务简报,集合地点,船只要求,活动规则等,公告将会自动发送给进入房间的玩家。",
placeholderStyle:
TextStyle(color: Colors.white.withOpacity(.4)),
),
const SizedBox(height: 32),
for (var v in [
"创建房间后,其他玩家可以在大厅首页看到您的房间和您选择的玩法,当一个玩家选择加入房间时,你们将可以互相看到对方的用户名。当房间人数达到最大玩家数时,将不再接受新的玩家加入。",
"这是《SC汉化盒子》提供的公益服务请勿滥用我们保留拒绝服务的权力。"
]) ...[
Text(
v,
style: TextStyle(
fontSize: 14, color: Colors.white.withOpacity(.6)),
),
const SizedBox(height: 6),
],
]
],
),
),
),
actions: [
if (model.isWorking)
const ProgressRing()
else
FilledButton(
onPressed: model.onSubmit(),
child: const Padding(
padding: EdgeInsets.all(3),
child: Text("创建房间"),
))
],
);
}
List<Widget> makeSubTypeSelectWidgets(
BuildContext context, PartyRoomCreateDialogUIModel model) {
bool isItemSelected(RoomSubtype subtype) {
return model.selectedSubType.contains(subtype);
}
return [
const SizedBox(height: 24),
const Text("标签(可选)"),
const SizedBox(height: 12),
Row(
children: [
for (var item in model.selectedRoomType!.subTypes)
Container(
decoration: BoxDecoration(
color: isItemSelected(item)
? Colors.green
: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(1000)),
padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 12),
margin: const EdgeInsets.only(right: 12),
child: IconButton(
icon: Row(
children: [
Icon(isItemSelected(item)
? FluentIcons.check_mark
: FluentIcons.add),
const SizedBox(width: 12),
Text(
item.name,
style: TextStyle(
fontSize: 13,
color: isItemSelected(item)
? null
: Colors.white.withOpacity(.4)),
),
],
),
onPressed: () => model.onTapSubType(item)),
)
],
)
];
}
Widget makeTitle(BuildContext context, PartyRoomCreateDialogUIModel model) {
return Row(
children: [
IconButton(
icon: const Icon(
FluentIcons.back,
size: 22,
),
onPressed: model.onBack()),
const SizedBox(width: 12),
Text(getUITitle(context, model)),
],
);
}
@override
String getUITitle(BuildContext context, PartyRoomCreateDialogUIModel model) =>
"创建房间";
}

View File

@ -0,0 +1,78 @@
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/common/conf.dart';
import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pb.dart';
import 'package:starcitizen_doctor/global_ui_model.dart';
import 'package:starcitizen_doctor/grpc/party_room_server.dart';
class PartyRoomCreateDialogUIModel extends BaseUIModel {
Map<String?, RoomType> roomTypes;
RoomType? selectedRoomType;
List<RoomSubtype> selectedSubType = [];
PartyRoomCreateDialogUIModel(this.roomTypes);
String? userName;
bool isWorking = false;
final playerMaxCtrl = TextEditingController(text: "8");
final announcementCtrl = TextEditingController();
@override
initModel() {
super.initModel();
roomTypes.removeWhere((key, value) => key == "");
}
@override
loadData() async {
userName = await globalUIModel.getRunningGameUser();
notifyListeners();
}
onBack() {
if (isWorking) return null;
return () {
Navigator.pop(context!);
};
}
void onChangeRoomType(RoomType? value) {
selectedSubType = [];
selectedRoomType = value;
notifyListeners();
}
onTapSubType(RoomSubtype item) {
if (!selectedSubType.contains(item)) {
selectedSubType.add(item);
} else {
selectedSubType.remove(item);
}
notifyListeners();
}
onSubmit() {
final maxPlayer = int.tryParse(playerMaxCtrl.text) ?? 0;
if (selectedRoomType == null) return null;
if (maxPlayer < 2 || maxPlayer > 32) return null;
return () async {
isWorking = true;
notifyListeners();
final room = await handleError(() => PartyRoomGrpcServer.createRoom(
RoomData(
roomTypeID: selectedRoomType?.id,
roomSubTypeIds: [for (var value in selectedSubType) value.id],
owner: userName,
deviceUUID: AppConf.deviceUUID,
announcement: announcementCtrl.text.trim())));
isWorking = false;
notifyListeners();
if (room != null) {
Navigator.pop(context!, room);
}
};
}
}

View File

@ -103,7 +103,7 @@ class PartyRoomHomeUI extends BaseUI<PartyRoomHomeUIModel> {
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
Button( Button(
onPressed: () {}, onPressed: () => model.onCreateRoom(),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(3), padding: EdgeInsets.all(3),
child: Row( child: Row(

View File

@ -2,6 +2,9 @@ import 'package:fixnum/fixnum.dart';
import 'package:starcitizen_doctor/base/ui_model.dart'; import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pb.dart'; import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pb.dart';
import 'package:starcitizen_doctor/grpc/party_room_server.dart'; import 'package:starcitizen_doctor/grpc/party_room_server.dart';
import 'package:starcitizen_doctor/ui/party_room/dialogs/party_room_create_dialog_ui_model.dart';
import 'dialogs/party_room_create_dialog_ui.dart';
class PartyRoomHomeUIModel extends BaseUIModel { class PartyRoomHomeUIModel extends BaseUIModel {
String? pingServerMessage; String? pingServerMessage;
@ -33,7 +36,7 @@ class PartyRoomHomeUIModel extends BaseUIModel {
RoomSortType selectedSortType = RoomSortType.Default; RoomSortType selectedSortType = RoomSortType.Default;
int pageNum = 1; int pageNum = 0;
List<RoomData>? rooms; List<RoomData>? rooms;
@ -48,17 +51,27 @@ class PartyRoomHomeUIModel extends BaseUIModel {
if (pingServerMessage != "") { if (pingServerMessage != "") {
pingServerMessage = null; pingServerMessage = null;
notifyListeners(); notifyListeners();
}
await _pingServer(); await _pingServer();
_loadPage(); }
await _loadPage();
}
@override
reloadData() async {
pageNum = 0;
rooms = null;
notifyListeners();
return super.reloadData();
} }
_loadPage() async { _loadPage() async {
final r = await PartyRoomGrpcServer.getRoomList(RoomListPageReqData( final r = await handleError(() => PartyRoomGrpcServer.getRoomList(
RoomListPageReqData(
pageNum: Int64.tryParseInt("$pageNum"), pageNum: Int64.tryParseInt("$pageNum"),
typeID: selectedRoomType?.id, typeID: selectedRoomType?.id,
subTypeID: selectedRoomSubType?.id, subTypeID: selectedRoomSubType?.id,
status: selectedStatus)); status: selectedStatus)));
if (r == null) return;
if (r.pageData.hasNext) { if (r.pageData.hasNext) {
pageNum++; pageNum++;
} else { } else {
@ -88,7 +101,7 @@ class PartyRoomHomeUIModel extends BaseUIModel {
selectedRoomType = selectedRoomType =
RoomType(id: "", name: "全部", desc: "查看所有类型的房间,寻找一起玩的伙伴。"); RoomType(id: "", name: "全部", desc: "查看所有类型的房间,寻找一起玩的伙伴。");
selectedRoomSubType = RoomSubtype(id: "", name: "全部"); selectedRoomSubType = RoomSubtype(id: "", name: "全部");
roomTypes = {null: selectedRoomType!}; roomTypes = {"": selectedRoomType!};
for (var element in r.roomTypes) { for (var element in r.roomTypes) {
roomTypes![element.id] = element; roomTypes![element.id] = element;
} }
@ -110,24 +123,42 @@ class PartyRoomHomeUIModel extends BaseUIModel {
void onChangeRoomType(RoomType? value) { void onChangeRoomType(RoomType? value) {
selectedRoomType = value; selectedRoomType = value;
selectedRoomSubType = null; selectedRoomSubType = null;
reloadData();
notifyListeners(); notifyListeners();
} }
void onChangeRoomStatus(RoomStatus? value) { void onChangeRoomStatus(RoomStatus? value) {
if (value == null) return; if (value == null) return;
selectedStatus = value; selectedStatus = value;
reloadData();
notifyListeners(); notifyListeners();
} }
void onChangeRoomSort(RoomSortType? value) { void onChangeRoomSort(RoomSortType? value) {
if (value == null) return; if (value == null) return;
selectedSortType = value; selectedSortType = value;
reloadData();
notifyListeners(); notifyListeners();
} }
void onChangeRoomSubType(RoomSubtype? value) { void onChangeRoomSubType(RoomSubtype? value) {
if (value == null) return; if (value == null) return;
selectedRoomSubType = value; selectedRoomSubType = value;
reloadData();
notifyListeners(); notifyListeners();
} }
onCreateRoom() async {
final room = await showDialog(
context: context!,
dismissWithEsc: false,
builder: (BuildContext context) {
return BaseUIContainer(
uiCreate: () => PartyRoomCreateDialogUI(),
modelCreate: () =>
PartyRoomCreateDialogUIModel(Map.from(roomTypes!)));
},
);
dPrint(room);
}
} }

View File

@ -32,7 +32,7 @@ dependencies:
sdk: flutter sdk: flutter
flutter_riverpod: ^2.3.6 flutter_riverpod: ^2.3.6
window_manager: ^0.3.2 window_manager: ^0.3.2
fluent_ui: ^4.8.1 fluent_ui: ^4.8.5
flutter_staggered_grid_view: ^0.7.0 flutter_staggered_grid_view: ^0.7.0
flutter_acrylic: ^1.1.0 flutter_acrylic: ^1.1.0
url_launcher: ^6.1.10 url_launcher: ^6.1.10