[Party Room] 加入房间功能

This commit is contained in:
xkeyC 2024-01-14 20:47:15 +08:00
parent 839125528b
commit 828785ced4
16 changed files with 1186 additions and 99 deletions

View File

@ -64,7 +64,7 @@ class BaseUIModel extends ChangeNotifier {
dPrint("$runtimeType.handleError Error:$e"); dPrint("$runtimeType.handleError Error:$e");
String errorMsg = "Unknown Error"; String errorMsg = "Unknown Error";
if (e is GrpcError) { if (e is GrpcError) {
errorMsg = "服务器错误 ${e.message} ?? Unknown Error"; errorMsg = "远程服务器消息 ${e.message ?? "Unknown Error"}";
} else { } else {
errorMsg = e.toString(); errorMsg = e.toString();
} }
@ -112,7 +112,10 @@ class BaseUIModel extends ChangeNotifier {
return _childUIProviders![modelKey]!; return _childUIProviders![modelKey]!;
} }
T? getCreatedChildUIModel<T extends BaseUIModel>(String modelKey) { T? getCreatedChildUIModel<T extends BaseUIModel>(String modelKey,{bool create = false}) {
if (create && _childUIModels?[modelKey] == null) {
_getChildUIModel(modelKey);
}
return _childUIModels?[modelKey] as T?; return _childUIModels?[modelKey] as T?;
} }

View File

@ -34,4 +34,15 @@ class PartyRoomGrpcServer {
static Future<RoomData> createRoom(RoomData roomData) async { static Future<RoomData> createRoom(RoomData roomData) async {
return await _indexService.createRoom(roomData); return await _indexService.createRoom(roomData);
} }
static Future<RoomData?> touchUserRoom(String userName, String deviceUUID) {
return _indexService
.touchUser(PreUser(userName: userName, deviceUUID: deviceUUID));
}
static ResponseStream<RoomUpdateMessage> joinRoom(
String roomID, String userName, String deviceUUID) {
return _indexService.joinRoom(
PreUser(roomID: roomID, userName: userName, deviceUUID: deviceUUID));
}
} }

View File

@ -0,0 +1,128 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
import 'chat.pbenum.dart';
export 'chat.pbenum.dart';
class ChatMessage extends $pb.GeneratedMessage {
factory ChatMessage({
$core.String? senderID,
$core.String? receiverID,
ReceiverType? receiverType,
MessageType? messageType,
$core.String? data,
}) {
final $result = create();
if (senderID != null) {
$result.senderID = senderID;
}
if (receiverID != null) {
$result.receiverID = receiverID;
}
if (receiverType != null) {
$result.receiverType = receiverType;
}
if (messageType != null) {
$result.messageType = messageType;
}
if (data != null) {
$result.data = data;
}
return $result;
}
ChatMessage._() : super();
factory ChatMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory ChatMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ChatMessage', createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'senderID', protoName: 'senderID')
..aOS(2, _omitFieldNames ? '' : 'receiverID', protoName: 'receiverID')
..e<ReceiverType>(3, _omitFieldNames ? '' : 'receiverType', $pb.PbFieldType.OE, protoName: 'receiverType', defaultOrMaker: ReceiverType.RoomMsg, valueOf: ReceiverType.valueOf, enumValues: ReceiverType.values)
..e<MessageType>(4, _omitFieldNames ? '' : 'messageType', $pb.PbFieldType.OE, protoName: 'messageType', defaultOrMaker: MessageType.System, valueOf: MessageType.valueOf, enumValues: MessageType.values)
..aOS(5, _omitFieldNames ? '' : 'data')
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
ChatMessage clone() => ChatMessage()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
ChatMessage copyWith(void Function(ChatMessage) updates) => super.copyWith((message) => updates(message as ChatMessage)) as ChatMessage;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static ChatMessage create() => ChatMessage._();
ChatMessage createEmptyInstance() => create();
static $pb.PbList<ChatMessage> createRepeated() => $pb.PbList<ChatMessage>();
@$core.pragma('dart2js:noInline')
static ChatMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ChatMessage>(create);
static ChatMessage? _defaultInstance;
@$pb.TagNumber(1)
$core.String get senderID => $_getSZ(0);
@$pb.TagNumber(1)
set senderID($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasSenderID() => $_has(0);
@$pb.TagNumber(1)
void clearSenderID() => clearField(1);
@$pb.TagNumber(2)
$core.String get receiverID => $_getSZ(1);
@$pb.TagNumber(2)
set receiverID($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasReceiverID() => $_has(1);
@$pb.TagNumber(2)
void clearReceiverID() => clearField(2);
@$pb.TagNumber(3)
ReceiverType get receiverType => $_getN(2);
@$pb.TagNumber(3)
set receiverType(ReceiverType v) { setField(3, v); }
@$pb.TagNumber(3)
$core.bool hasReceiverType() => $_has(2);
@$pb.TagNumber(3)
void clearReceiverType() => clearField(3);
@$pb.TagNumber(4)
MessageType get messageType => $_getN(3);
@$pb.TagNumber(4)
set messageType(MessageType v) { setField(4, v); }
@$pb.TagNumber(4)
$core.bool hasMessageType() => $_has(3);
@$pb.TagNumber(4)
void clearMessageType() => clearField(4);
@$pb.TagNumber(5)
$core.String get data => $_getSZ(4);
@$pb.TagNumber(5)
set data($core.String v) { $_setString(4, v); }
@$pb.TagNumber(5)
$core.bool hasData() => $_has(4);
@$pb.TagNumber(5)
void clearData() => clearField(5);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');

View File

@ -0,0 +1,51 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class ReceiverType extends $pb.ProtobufEnum {
static const ReceiverType RoomMsg = ReceiverType._(0, _omitEnumNames ? '' : 'RoomMsg');
static const ReceiverType PrivateMsg = ReceiverType._(1, _omitEnumNames ? '' : 'PrivateMsg');
static const $core.List<ReceiverType> values = <ReceiverType> [
RoomMsg,
PrivateMsg,
];
static final $core.Map<$core.int, ReceiverType> _byValue = $pb.ProtobufEnum.initByValue(values);
static ReceiverType? valueOf($core.int value) => _byValue[value];
const ReceiverType._($core.int v, $core.String n) : super(v, n);
}
class MessageType extends $pb.ProtobufEnum {
static const MessageType System = MessageType._(0, _omitEnumNames ? '' : 'System');
static const MessageType Text = MessageType._(1, _omitEnumNames ? '' : 'Text');
static const MessageType Image = MessageType._(2, _omitEnumNames ? '' : 'Image');
static const MessageType Markdown = MessageType._(3, _omitEnumNames ? '' : 'Markdown');
static const $core.List<MessageType> values = <MessageType> [
System,
Text,
Image,
Markdown,
];
static final $core.Map<$core.int, MessageType> _byValue = $pb.ProtobufEnum.initByValue(values);
static MessageType? valueOf($core.int value) => _byValue[value];
const MessageType._($core.int v, $core.String n) : super(v, n);
}
const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');

View File

@ -0,0 +1,80 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:async' as $async;
import 'dart:core' as $core;
import 'package:grpc/service_api.dart' as $grpc;
import 'package:protobuf/protobuf.dart' as $pb;
import 'chat.pb.dart' as $1;
import 'index.pb.dart' as $0;
export 'chat.pb.dart';
@$pb.GrpcServiceName('ChatService')
class ChatServiceClient extends $grpc.Client {
static final _$listenMessage = $grpc.ClientMethod<$0.PreUser, $1.ChatMessage>(
'/ChatService/ListenMessage',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) => $1.ChatMessage.fromBuffer(value));
static final _$sendMessage = $grpc.ClientMethod<$1.ChatMessage, $0.BaseRespData>(
'/ChatService/SendMessage',
($1.ChatMessage value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.BaseRespData.fromBuffer(value));
ChatServiceClient($grpc.ClientChannel channel,
{$grpc.CallOptions? options,
$core.Iterable<$grpc.ClientInterceptor>? interceptors})
: super(channel, options: options,
interceptors: interceptors);
$grpc.ResponseStream<$1.ChatMessage> listenMessage($0.PreUser request, {$grpc.CallOptions? options}) {
return $createStreamingCall(_$listenMessage, $async.Stream.fromIterable([request]), options: options);
}
$grpc.ResponseFuture<$0.BaseRespData> sendMessage($1.ChatMessage request, {$grpc.CallOptions? options}) {
return $createUnaryCall(_$sendMessage, request, options: options);
}
}
@$pb.GrpcServiceName('ChatService')
abstract class ChatServiceBase extends $grpc.Service {
$core.String get $name => 'ChatService';
ChatServiceBase() {
$addMethod($grpc.ServiceMethod<$0.PreUser, $1.ChatMessage>(
'ListenMessage',
listenMessage_Pre,
false,
true,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($1.ChatMessage value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$1.ChatMessage, $0.BaseRespData>(
'SendMessage',
sendMessage_Pre,
false,
false,
($core.List<$core.int> value) => $1.ChatMessage.fromBuffer(value),
($0.BaseRespData value) => value.writeToBuffer()));
}
$async.Stream<$1.ChatMessage> listenMessage_Pre($grpc.ServiceCall call, $async.Future<$0.PreUser> request) async* {
yield* listenMessage(call, await request);
}
$async.Future<$0.BaseRespData> sendMessage_Pre($grpc.ServiceCall call, $async.Future<$1.ChatMessage> request) async {
return sendMessage(call, await request);
}
$async.Stream<$1.ChatMessage> listenMessage($grpc.ServiceCall call, $0.PreUser request);
$async.Future<$0.BaseRespData> sendMessage($grpc.ServiceCall call, $1.ChatMessage request);
}

View File

@ -0,0 +1,63 @@
//
// Generated code. Do not modify.
// source: chat.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use receiverTypeDescriptor instead')
const ReceiverType$json = {
'1': 'ReceiverType',
'2': [
{'1': 'RoomMsg', '2': 0},
{'1': 'PrivateMsg', '2': 1},
],
};
/// Descriptor for `ReceiverType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List receiverTypeDescriptor = $convert.base64Decode(
'CgxSZWNlaXZlclR5cGUSCwoHUm9vbU1zZxAAEg4KClByaXZhdGVNc2cQAQ==');
@$core.Deprecated('Use messageTypeDescriptor instead')
const MessageType$json = {
'1': 'MessageType',
'2': [
{'1': 'System', '2': 0},
{'1': 'Text', '2': 1},
{'1': 'Image', '2': 2},
{'1': 'Markdown', '2': 3},
],
};
/// Descriptor for `MessageType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List messageTypeDescriptor = $convert.base64Decode(
'CgtNZXNzYWdlVHlwZRIKCgZTeXN0ZW0QABIICgRUZXh0EAESCQoFSW1hZ2UQAhIMCghNYXJrZG'
'93bhAD');
@$core.Deprecated('Use chatMessageDescriptor instead')
const ChatMessage$json = {
'1': 'ChatMessage',
'2': [
{'1': 'senderID', '3': 1, '4': 1, '5': 9, '10': 'senderID'},
{'1': 'receiverID', '3': 2, '4': 1, '5': 9, '10': 'receiverID'},
{'1': 'receiverType', '3': 3, '4': 1, '5': 14, '6': '.ReceiverType', '10': 'receiverType'},
{'1': 'messageType', '3': 4, '4': 1, '5': 14, '6': '.MessageType', '10': 'messageType'},
{'1': 'data', '3': 5, '4': 1, '5': 9, '10': 'data'},
],
};
/// Descriptor for `ChatMessage`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List chatMessageDescriptor = $convert.base64Decode(
'CgtDaGF0TWVzc2FnZRIaCghzZW5kZXJJRBgBIAEoCVIIc2VuZGVySUQSHgoKcmVjZWl2ZXJJRB'
'gCIAEoCVIKcmVjZWl2ZXJJRBIxCgxyZWNlaXZlclR5cGUYAyABKA4yDS5SZWNlaXZlclR5cGVS'
'DHJlY2VpdmVyVHlwZRIuCgttZXNzYWdlVHlwZRgEIAEoDjIMLk1lc3NhZ2VUeXBlUgttZXNzYW'
'dlVHlwZRISCgRkYXRhGAUgASgJUgRkYXRh');

View File

@ -519,6 +519,7 @@ class RoomData extends $pb.GeneratedMessage {
$core.String? deviceUUID, $core.String? deviceUUID,
$core.String? announcement, $core.String? announcement,
$core.String? avatar, $core.String? avatar,
$fixnum.Int64? updateTime,
}) { }) {
final $result = create(); final $result = create();
if (id != null) { if (id != null) {
@ -554,6 +555,9 @@ class RoomData extends $pb.GeneratedMessage {
if (avatar != null) { if (avatar != null) {
$result.avatar = avatar; $result.avatar = avatar;
} }
if (updateTime != null) {
$result.updateTime = updateTime;
}
return $result; return $result;
} }
RoomData._() : super(); RoomData._() : super();
@ -572,6 +576,7 @@ class RoomData extends $pb.GeneratedMessage {
..aOS(9, _omitFieldNames ? '' : 'deviceUUID', protoName: 'deviceUUID') ..aOS(9, _omitFieldNames ? '' : 'deviceUUID', protoName: 'deviceUUID')
..aOS(10, _omitFieldNames ? '' : 'announcement') ..aOS(10, _omitFieldNames ? '' : 'announcement')
..aOS(11, _omitFieldNames ? '' : 'avatar') ..aOS(11, _omitFieldNames ? '' : 'avatar')
..aInt64(12, _omitFieldNames ? '' : 'updateTime', protoName: 'updateTime')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -688,6 +693,15 @@ class RoomData extends $pb.GeneratedMessage {
$core.bool hasAvatar() => $_has(10); $core.bool hasAvatar() => $_has(10);
@$pb.TagNumber(11) @$pb.TagNumber(11)
void clearAvatar() => clearField(11); void clearAvatar() => clearField(11);
@$pb.TagNumber(12)
$fixnum.Int64 get updateTime => $_getI64(11);
@$pb.TagNumber(12)
set updateTime($fixnum.Int64 v) { $_setInt64(11, v); }
@$pb.TagNumber(12)
$core.bool hasUpdateTime() => $_has(11);
@$pb.TagNumber(12)
void clearUpdateTime() => clearField(12);
} }
class RoomListPageReqData extends $pb.GeneratedMessage { class RoomListPageReqData extends $pb.GeneratedMessage {
@ -856,6 +870,250 @@ class RoomListData extends $pb.GeneratedMessage {
$core.List<RoomData> get rooms => $_getList(1); $core.List<RoomData> get rooms => $_getList(1);
} }
class PreUser extends $pb.GeneratedMessage {
factory PreUser({
$core.String? userName,
$core.String? deviceUUID,
$core.String? roomID,
}) {
final $result = create();
if (userName != null) {
$result.userName = userName;
}
if (deviceUUID != null) {
$result.deviceUUID = deviceUUID;
}
if (roomID != null) {
$result.roomID = roomID;
}
return $result;
}
PreUser._() : super();
factory PreUser.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory PreUser.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PreUser', createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'userName', protoName: 'userName')
..aOS(2, _omitFieldNames ? '' : 'deviceUUID', protoName: 'deviceUUID')
..aOS(3, _omitFieldNames ? '' : 'roomID', protoName: 'roomID')
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
PreUser clone() => PreUser()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
PreUser copyWith(void Function(PreUser) updates) => super.copyWith((message) => updates(message as PreUser)) as PreUser;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static PreUser create() => PreUser._();
PreUser createEmptyInstance() => create();
static $pb.PbList<PreUser> createRepeated() => $pb.PbList<PreUser>();
@$core.pragma('dart2js:noInline')
static PreUser getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<PreUser>(create);
static PreUser? _defaultInstance;
@$pb.TagNumber(1)
$core.String get userName => $_getSZ(0);
@$pb.TagNumber(1)
set userName($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasUserName() => $_has(0);
@$pb.TagNumber(1)
void clearUserName() => clearField(1);
@$pb.TagNumber(2)
$core.String get deviceUUID => $_getSZ(1);
@$pb.TagNumber(2)
set deviceUUID($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasDeviceUUID() => $_has(1);
@$pb.TagNumber(2)
void clearDeviceUUID() => clearField(2);
@$pb.TagNumber(3)
$core.String get roomID => $_getSZ(2);
@$pb.TagNumber(3)
set roomID($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasRoomID() => $_has(2);
@$pb.TagNumber(3)
void clearRoomID() => clearField(3);
}
class RoomUserData extends $pb.GeneratedMessage {
factory RoomUserData({
$core.String? id,
$core.String? playerName,
$core.String? avatar,
RoomUserStatus? status,
}) {
final $result = create();
if (id != null) {
$result.id = id;
}
if (playerName != null) {
$result.playerName = playerName;
}
if (avatar != null) {
$result.avatar = avatar;
}
if (status != null) {
$result.status = status;
}
return $result;
}
RoomUserData._() : super();
factory RoomUserData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory RoomUserData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'RoomUserData', createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'id')
..aOS(2, _omitFieldNames ? '' : 'playerName', protoName: 'playerName')
..aOS(3, _omitFieldNames ? '' : 'Avatar', protoName: 'Avatar')
..e<RoomUserStatus>(4, _omitFieldNames ? '' : 'status', $pb.PbFieldType.OE, defaultOrMaker: RoomUserStatus.RoomUserStatusJoin, valueOf: RoomUserStatus.valueOf, enumValues: RoomUserStatus.values)
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
RoomUserData clone() => RoomUserData()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
RoomUserData copyWith(void Function(RoomUserData) updates) => super.copyWith((message) => updates(message as RoomUserData)) as RoomUserData;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static RoomUserData create() => RoomUserData._();
RoomUserData createEmptyInstance() => create();
static $pb.PbList<RoomUserData> createRepeated() => $pb.PbList<RoomUserData>();
@$core.pragma('dart2js:noInline')
static RoomUserData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<RoomUserData>(create);
static RoomUserData? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
@$pb.TagNumber(1)
set id($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasId() => $_has(0);
@$pb.TagNumber(1)
void clearId() => clearField(1);
@$pb.TagNumber(2)
$core.String get playerName => $_getSZ(1);
@$pb.TagNumber(2)
set playerName($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasPlayerName() => $_has(1);
@$pb.TagNumber(2)
void clearPlayerName() => clearField(2);
@$pb.TagNumber(3)
$core.String get avatar => $_getSZ(2);
@$pb.TagNumber(3)
set avatar($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasAvatar() => $_has(2);
@$pb.TagNumber(3)
void clearAvatar() => clearField(3);
@$pb.TagNumber(4)
RoomUserStatus get status => $_getN(3);
@$pb.TagNumber(4)
set status(RoomUserStatus v) { setField(4, v); }
@$pb.TagNumber(4)
$core.bool hasStatus() => $_has(3);
@$pb.TagNumber(4)
void clearStatus() => clearField(4);
}
class RoomUpdateMessage extends $pb.GeneratedMessage {
factory RoomUpdateMessage({
RoomData? roomData,
$core.Iterable<RoomUserData>? usersData,
RoomUpdateType? roomUpdateType,
}) {
final $result = create();
if (roomData != null) {
$result.roomData = roomData;
}
if (usersData != null) {
$result.usersData.addAll(usersData);
}
if (roomUpdateType != null) {
$result.roomUpdateType = roomUpdateType;
}
return $result;
}
RoomUpdateMessage._() : super();
factory RoomUpdateMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory RoomUpdateMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'RoomUpdateMessage', createEmptyInstance: create)
..aOM<RoomData>(1, _omitFieldNames ? '' : 'roomData', protoName: 'roomData', subBuilder: RoomData.create)
..pc<RoomUserData>(2, _omitFieldNames ? '' : 'usersData', $pb.PbFieldType.PM, protoName: 'usersData', subBuilder: RoomUserData.create)
..e<RoomUpdateType>(3, _omitFieldNames ? '' : 'roomUpdateType', $pb.PbFieldType.OE, protoName: 'roomUpdateType', defaultOrMaker: RoomUpdateType.RoomUpdateData, valueOf: RoomUpdateType.valueOf, enumValues: RoomUpdateType.values)
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
RoomUpdateMessage clone() => RoomUpdateMessage()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
RoomUpdateMessage copyWith(void Function(RoomUpdateMessage) updates) => super.copyWith((message) => updates(message as RoomUpdateMessage)) as RoomUpdateMessage;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static RoomUpdateMessage create() => RoomUpdateMessage._();
RoomUpdateMessage createEmptyInstance() => create();
static $pb.PbList<RoomUpdateMessage> createRepeated() => $pb.PbList<RoomUpdateMessage>();
@$core.pragma('dart2js:noInline')
static RoomUpdateMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<RoomUpdateMessage>(create);
static RoomUpdateMessage? _defaultInstance;
@$pb.TagNumber(1)
RoomData get roomData => $_getN(0);
@$pb.TagNumber(1)
set roomData(RoomData v) { setField(1, v); }
@$pb.TagNumber(1)
$core.bool hasRoomData() => $_has(0);
@$pb.TagNumber(1)
void clearRoomData() => clearField(1);
@$pb.TagNumber(1)
RoomData ensureRoomData() => $_ensure(0);
@$pb.TagNumber(2)
$core.List<RoomUserData> get usersData => $_getList(1);
@$pb.TagNumber(3)
RoomUpdateType get roomUpdateType => $_getN(2);
@$pb.TagNumber(3)
set roomUpdateType(RoomUpdateType v) { setField(3, v); }
@$pb.TagNumber(3)
$core.bool hasRoomUpdateType() => $_has(2);
@$pb.TagNumber(3)
void clearRoomUpdateType() => clearField(3);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');

View File

@ -59,5 +59,39 @@ class RoomSortType extends $pb.ProtobufEnum {
const RoomSortType._($core.int v, $core.String n) : super(v, n); const RoomSortType._($core.int v, $core.String n) : super(v, n);
} }
class RoomUserStatus extends $pb.ProtobufEnum {
static const RoomUserStatus RoomUserStatusJoin = RoomUserStatus._(0, _omitEnumNames ? '' : 'RoomUserStatusJoin');
static const RoomUserStatus RoomUserStatusLostOffline = RoomUserStatus._(1, _omitEnumNames ? '' : 'RoomUserStatusLostOffline');
static const RoomUserStatus RoomUserStatusLeave = RoomUserStatus._(2, _omitEnumNames ? '' : 'RoomUserStatusLeave');
static const RoomUserStatus RoomUserStatusWaitingConnect = RoomUserStatus._(3, _omitEnumNames ? '' : 'RoomUserStatusWaitingConnect');
static const $core.List<RoomUserStatus> values = <RoomUserStatus> [
RoomUserStatusJoin,
RoomUserStatusLostOffline,
RoomUserStatusLeave,
RoomUserStatusWaitingConnect,
];
static final $core.Map<$core.int, RoomUserStatus> _byValue = $pb.ProtobufEnum.initByValue(values);
static RoomUserStatus? valueOf($core.int value) => _byValue[value];
const RoomUserStatus._($core.int v, $core.String n) : super(v, n);
}
class RoomUpdateType extends $pb.ProtobufEnum {
static const RoomUpdateType RoomUpdateData = RoomUpdateType._(0, _omitEnumNames ? '' : 'RoomUpdateData');
static const RoomUpdateType RoomClose = RoomUpdateType._(1, _omitEnumNames ? '' : 'RoomClose');
static const $core.List<RoomUpdateType> values = <RoomUpdateType> [
RoomUpdateData,
RoomClose,
];
static final $core.Map<$core.int, RoomUpdateType> _byValue = $pb.ProtobufEnum.initByValue(values);
static RoomUpdateType? valueOf($core.int value) => _byValue[value];
const RoomUpdateType._($core.int v, $core.String n) : super(v, n);
}
const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');

View File

@ -37,6 +37,18 @@ class IndexServiceClient extends $grpc.Client {
'/IndexService/GetRoomList', '/IndexService/GetRoomList',
($0.RoomListPageReqData value) => value.writeToBuffer(), ($0.RoomListPageReqData value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.RoomListData.fromBuffer(value)); ($core.List<$core.int> value) => $0.RoomListData.fromBuffer(value));
static final _$touchUser = $grpc.ClientMethod<$0.PreUser, $0.RoomData>(
'/IndexService/TouchUser',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.RoomData.fromBuffer(value));
static final _$joinRoom = $grpc.ClientMethod<$0.PreUser, $0.RoomUpdateMessage>(
'/IndexService/JoinRoom',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.RoomUpdateMessage.fromBuffer(value));
static final _$leaveRoom = $grpc.ClientMethod<$0.PreUser, $0.BaseRespData>(
'/IndexService/LeaveRoom',
($0.PreUser value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.BaseRespData.fromBuffer(value));
IndexServiceClient($grpc.ClientChannel channel, IndexServiceClient($grpc.ClientChannel channel,
{$grpc.CallOptions? options, {$grpc.CallOptions? options,
@ -59,6 +71,18 @@ class IndexServiceClient extends $grpc.Client {
$grpc.ResponseFuture<$0.RoomListData> getRoomList($0.RoomListPageReqData request, {$grpc.CallOptions? options}) { $grpc.ResponseFuture<$0.RoomListData> getRoomList($0.RoomListPageReqData request, {$grpc.CallOptions? options}) {
return $createUnaryCall(_$getRoomList, request, options: options); return $createUnaryCall(_$getRoomList, request, options: options);
} }
$grpc.ResponseFuture<$0.RoomData> touchUser($0.PreUser request, {$grpc.CallOptions? options}) {
return $createUnaryCall(_$touchUser, request, options: options);
}
$grpc.ResponseStream<$0.RoomUpdateMessage> joinRoom($0.PreUser request, {$grpc.CallOptions? options}) {
return $createStreamingCall(_$joinRoom, $async.Stream.fromIterable([request]), options: options);
}
$grpc.ResponseFuture<$0.BaseRespData> leaveRoom($0.PreUser request, {$grpc.CallOptions? options}) {
return $createUnaryCall(_$leaveRoom, request, options: options);
}
} }
@$pb.GrpcServiceName('IndexService') @$pb.GrpcServiceName('IndexService')
@ -94,6 +118,27 @@ abstract class IndexServiceBase extends $grpc.Service {
false, false,
($core.List<$core.int> value) => $0.RoomListPageReqData.fromBuffer(value), ($core.List<$core.int> value) => $0.RoomListPageReqData.fromBuffer(value),
($0.RoomListData value) => value.writeToBuffer())); ($0.RoomListData value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.PreUser, $0.RoomData>(
'TouchUser',
touchUser_Pre,
false,
false,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($0.RoomData value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.PreUser, $0.RoomUpdateMessage>(
'JoinRoom',
joinRoom_Pre,
false,
true,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($0.RoomUpdateMessage value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.PreUser, $0.BaseRespData>(
'LeaveRoom',
leaveRoom_Pre,
false,
false,
($core.List<$core.int> value) => $0.PreUser.fromBuffer(value),
($0.BaseRespData value) => value.writeToBuffer()));
} }
$async.Future<$0.PingData> pingServer_Pre($grpc.ServiceCall call, $async.Future<$0.PingData> request) async { $async.Future<$0.PingData> pingServer_Pre($grpc.ServiceCall call, $async.Future<$0.PingData> request) async {
@ -112,8 +157,23 @@ abstract class IndexServiceBase extends $grpc.Service {
return getRoomList(call, await request); return getRoomList(call, await request);
} }
$async.Future<$0.RoomData> touchUser_Pre($grpc.ServiceCall call, $async.Future<$0.PreUser> request) async {
return touchUser(call, await request);
}
$async.Stream<$0.RoomUpdateMessage> joinRoom_Pre($grpc.ServiceCall call, $async.Future<$0.PreUser> request) async* {
yield* joinRoom(call, await request);
}
$async.Future<$0.BaseRespData> leaveRoom_Pre($grpc.ServiceCall call, $async.Future<$0.PreUser> request) async {
return leaveRoom(call, await request);
}
$async.Future<$0.PingData> pingServer($grpc.ServiceCall call, $0.PingData request); $async.Future<$0.PingData> pingServer($grpc.ServiceCall call, $0.PingData request);
$async.Future<$0.RoomTypesData> getRoomTypes($grpc.ServiceCall call, $0.Empty request); $async.Future<$0.RoomTypesData> getRoomTypes($grpc.ServiceCall call, $0.Empty request);
$async.Future<$0.RoomData> createRoom($grpc.ServiceCall call, $0.RoomData request); $async.Future<$0.RoomData> createRoom($grpc.ServiceCall call, $0.RoomData request);
$async.Future<$0.RoomListData> getRoomList($grpc.ServiceCall call, $0.RoomListPageReqData request); $async.Future<$0.RoomListData> getRoomList($grpc.ServiceCall call, $0.RoomListPageReqData request);
$async.Future<$0.RoomData> touchUser($grpc.ServiceCall call, $0.PreUser request);
$async.Stream<$0.RoomUpdateMessage> joinRoom($grpc.ServiceCall call, $0.PreUser request);
$async.Future<$0.BaseRespData> leaveRoom($grpc.ServiceCall call, $0.PreUser request);
} }

View File

@ -50,6 +50,36 @@ final $typed_data.Uint8List roomSortTypeDescriptor = $convert.base64Decode(
'5pbXVtUGxheWVyTnVtYmVyEAISEwoPUmVjZW50bHlDcmVhdGVkEAMSEQoNT2xkZXN0Q3JlYXRl' '5pbXVtUGxheWVyTnVtYmVyEAISEwoPUmVjZW50bHlDcmVhdGVkEAMSEQoNT2xkZXN0Q3JlYXRl'
'ZBAE'); 'ZBAE');
@$core.Deprecated('Use roomUserStatusDescriptor instead')
const RoomUserStatus$json = {
'1': 'RoomUserStatus',
'2': [
{'1': 'RoomUserStatusJoin', '2': 0},
{'1': 'RoomUserStatusLostOffline', '2': 1},
{'1': 'RoomUserStatusLeave', '2': 2},
{'1': 'RoomUserStatusWaitingConnect', '2': 3},
],
};
/// Descriptor for `RoomUserStatus`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List roomUserStatusDescriptor = $convert.base64Decode(
'Cg5Sb29tVXNlclN0YXR1cxIWChJSb29tVXNlclN0YXR1c0pvaW4QABIdChlSb29tVXNlclN0YX'
'R1c0xvc3RPZmZsaW5lEAESFwoTUm9vbVVzZXJTdGF0dXNMZWF2ZRACEiAKHFJvb21Vc2VyU3Rh'
'dHVzV2FpdGluZ0Nvbm5lY3QQAw==');
@$core.Deprecated('Use roomUpdateTypeDescriptor instead')
const RoomUpdateType$json = {
'1': 'RoomUpdateType',
'2': [
{'1': 'RoomUpdateData', '2': 0},
{'1': 'RoomClose', '2': 1},
],
};
/// Descriptor for `RoomUpdateType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List roomUpdateTypeDescriptor = $convert.base64Decode(
'Cg5Sb29tVXBkYXRlVHlwZRISCg5Sb29tVXBkYXRlRGF0YRAAEg0KCVJvb21DbG9zZRAB');
@$core.Deprecated('Use emptyDescriptor instead') @$core.Deprecated('Use emptyDescriptor instead')
const Empty$json = { const Empty$json = {
'1': 'Empty', '1': 'Empty',
@ -165,6 +195,7 @@ const RoomData$json = {
{'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'}, {'1': 'announcement', '3': 10, '4': 1, '5': 9, '10': 'announcement'},
{'1': 'avatar', '3': 11, '4': 1, '5': 9, '10': 'avatar'}, {'1': 'avatar', '3': 11, '4': 1, '5': 9, '10': 'avatar'},
{'1': 'updateTime', '3': 12, '4': 1, '5': 3, '10': 'updateTime'},
], ],
}; };
@ -176,7 +207,7 @@ final $typed_data.Uint8List roomDataDescriptor = $convert.base64Decode(
'ABKANSCmNyZWF0ZVRpbWUSHAoJY3VyUGxheWVyGAcgASgFUgljdXJQbGF5ZXISIwoGc3RhdHVz' 'ABKANSCmNyZWF0ZVRpbWUSHAoJY3VyUGxheWVyGAcgASgFUgljdXJQbGF5ZXISIwoGc3RhdHVz'
'GAggASgOMgsuUm9vbVN0YXR1c1IGc3RhdHVzEh4KCmRldmljZVVVSUQYCSABKAlSCmRldmljZV' 'GAggASgOMgsuUm9vbVN0YXR1c1IGc3RhdHVzEh4KCmRldmljZVVVSUQYCSABKAlSCmRldmljZV'
'VVSUQSIgoMYW5ub3VuY2VtZW50GAogASgJUgxhbm5vdW5jZW1lbnQSFgoGYXZhdGFyGAsgASgJ' 'VVSUQSIgoMYW5ub3VuY2VtZW50GAogASgJUgxhbm5vdW5jZW1lbnQSFgoGYXZhdGFyGAsgASgJ'
'UgZhdmF0YXI='); 'UgZhdmF0YXISHgoKdXBkYXRlVGltZRgMIAEoA1IKdXBkYXRlVGltZQ==');
@$core.Deprecated('Use roomListPageReqDataDescriptor instead') @$core.Deprecated('Use roomListPageReqDataDescriptor instead')
const RoomListPageReqData$json = { const RoomListPageReqData$json = {
@ -211,3 +242,51 @@ final $typed_data.Uint8List roomListDataDescriptor = $convert.base64Decode(
'CgxSb29tTGlzdERhdGESLQoIcGFnZURhdGEYASABKAsyES5CYXNlUGFnZVJlc3BEYXRhUghwYW' 'CgxSb29tTGlzdERhdGESLQoIcGFnZURhdGEYASABKAsyES5CYXNlUGFnZVJlc3BEYXRhUghwYW'
'dlRGF0YRIfCgVyb29tcxgCIAMoCzIJLlJvb21EYXRhUgVyb29tcw=='); 'dlRGF0YRIfCgVyb29tcxgCIAMoCzIJLlJvb21EYXRhUgVyb29tcw==');
@$core.Deprecated('Use preUserDescriptor instead')
const PreUser$json = {
'1': 'PreUser',
'2': [
{'1': 'userName', '3': 1, '4': 1, '5': 9, '10': 'userName'},
{'1': 'deviceUUID', '3': 2, '4': 1, '5': 9, '10': 'deviceUUID'},
{'1': 'roomID', '3': 3, '4': 1, '5': 9, '10': 'roomID'},
],
};
/// Descriptor for `PreUser`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List preUserDescriptor = $convert.base64Decode(
'CgdQcmVVc2VyEhoKCHVzZXJOYW1lGAEgASgJUgh1c2VyTmFtZRIeCgpkZXZpY2VVVUlEGAIgAS'
'gJUgpkZXZpY2VVVUlEEhYKBnJvb21JRBgDIAEoCVIGcm9vbUlE');
@$core.Deprecated('Use roomUserDataDescriptor instead')
const RoomUserData$json = {
'1': 'RoomUserData',
'2': [
{'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
{'1': 'playerName', '3': 2, '4': 1, '5': 9, '10': 'playerName'},
{'1': 'Avatar', '3': 3, '4': 1, '5': 9, '10': 'Avatar'},
{'1': 'status', '3': 4, '4': 1, '5': 14, '6': '.RoomUserStatus', '10': 'status'},
],
};
/// Descriptor for `RoomUserData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomUserDataDescriptor = $convert.base64Decode(
'CgxSb29tVXNlckRhdGESDgoCaWQYASABKAlSAmlkEh4KCnBsYXllck5hbWUYAiABKAlSCnBsYX'
'llck5hbWUSFgoGQXZhdGFyGAMgASgJUgZBdmF0YXISJwoGc3RhdHVzGAQgASgOMg8uUm9vbVVz'
'ZXJTdGF0dXNSBnN0YXR1cw==');
@$core.Deprecated('Use roomUpdateMessageDescriptor instead')
const RoomUpdateMessage$json = {
'1': 'RoomUpdateMessage',
'2': [
{'1': 'roomData', '3': 1, '4': 1, '5': 11, '6': '.RoomData', '10': 'roomData'},
{'1': 'usersData', '3': 2, '4': 3, '5': 11, '6': '.RoomUserData', '10': 'usersData'},
{'1': 'roomUpdateType', '3': 3, '4': 1, '5': 14, '6': '.RoomUpdateType', '10': 'roomUpdateType'},
],
};
/// Descriptor for `RoomUpdateMessage`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List roomUpdateMessageDescriptor = $convert.base64Decode(
'ChFSb29tVXBkYXRlTWVzc2FnZRIlCghyb29tRGF0YRgBIAEoCzIJLlJvb21EYXRhUghyb29tRG'
'F0YRIrCgl1c2Vyc0RhdGEYAiADKAsyDS5Sb29tVXNlckRhdGFSCXVzZXJzRGF0YRI3Cg5yb29t'
'VXBkYXRlVHlwZRgDIAEoDjIPLlJvb21VcGRhdGVUeXBlUg5yb29tVXBkYXRlVHlwZQ==');

View File

@ -16,7 +16,7 @@ final globalUIModelProvider = ChangeNotifierProvider((ref) => globalUIModel);
class AppGlobalUIModel extends BaseUIModel { class AppGlobalUIModel extends BaseUIModel {
Timer? activityThemeColorTimer; Timer? activityThemeColorTimer;
Future<String> getRunningGameUser() async { Future<String?> getRunningGameUser() async {
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
///TODO ///TODO

View File

@ -1,8 +1,8 @@
import 'package:starcitizen_doctor/base/ui_model.dart'; import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/common/conf.dart'; import 'package:starcitizen_doctor/common/conf.dart';
import 'package:starcitizen_doctor/common/grpc/party_room_server.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/global_ui_model.dart'; import 'package:starcitizen_doctor/global_ui_model.dart';
import 'package:starcitizen_doctor/grpc/party_room_server.dart';
class PartyRoomCreateDialogUIModel extends BaseUIModel { class PartyRoomCreateDialogUIModel extends BaseUIModel {
Map<String?, RoomType> roomTypes; Map<String?, RoomType> roomTypes;

View File

@ -0,0 +1,148 @@
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_chat_ui_model.dart';
class PartyRoomChatUI extends BaseUI<PartyRoomChatUIModel> {
@override
Widget? buildBody(BuildContext context, PartyRoomChatUIModel model) {
final roomData = model.serverResultRoomData;
if (roomData == null) return makeLoading(context);
final typesMap = model.partyRoomHomeUIModel.roomTypes;
final title =
"${roomData.owner}${typesMap?[roomData.roomTypeID]?.name ?? roomData.roomTypeID}房间";
// final createTime =
// DateTime.fromMillisecondsSinceEpoch(roomData.createTime.toInt());
return Column(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: Colors.black.withOpacity(.25)),
child: makeTitleBar(model, title, roomData),
),
Expanded(
child: Row(
children: [
Container(
width: 220,
padding: const EdgeInsets.only(left: 12, right: 12),
decoration: BoxDecoration(color: Colors.black.withOpacity(.07)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 12),
makeItemRow("玩家数量:",
"${model.playersMap?.length ?? 0} / ${roomData.maxPlayer}"),
const SizedBox(height: 12),
if (model.playersMap == null)
Expanded(child: makeLoading(context))
else
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
final item = model.playersMap!.entries
.elementAt(index)
.value;
return Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: CacheNetImage(
url: item.avatar,
width: 28,
height: 28,
),
),
const SizedBox(width: 6),
Expanded(child: Text(item.playerName)),
const SizedBox(width: 12),
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.playerStatusMap[item.status] ?? item.status}",
style: const TextStyle(fontSize: 13),
),
)
],
);
},
itemCount: model.playersMap!.length,
),
)
],
),
),
],
),
)
],
);
}
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 makeTitleBar(
PartyRoomChatUIModel model, String title, RoomData roomData) {
return Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: CacheNetImage(
url: roomData.avatar,
width: 32,
height: 32,
),
),
const SizedBox(width: 12),
Text(
title,
style: const TextStyle(fontSize: 18),
),
const SizedBox(width: 12),
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.partyRoomHomeUIModel.roomStatus[roomData.status]}")),
const SizedBox(width: 12),
const Spacer(),
IconButton(
icon: const Icon(
FluentIcons.leave,
size: 20,
),
onPressed: () => model.onClose())
],
);
}
@override
String getUITitle(BuildContext context, PartyRoomChatUIModel model) => "Chat";
}

View File

@ -0,0 +1,93 @@
import 'package:grpc/grpc.dart';
import 'package:starcitizen_doctor/base/ui_model.dart';
import 'package:starcitizen_doctor/common/conf.dart';
import 'package:starcitizen_doctor/common/grpc/party_room_server.dart';
import 'package:starcitizen_doctor/generated/grpc/party_room_server/index.pb.dart';
import 'package:starcitizen_doctor/global_ui_model.dart';
import 'party_room_home_ui_model.dart';
class PartyRoomChatUIModel extends BaseUIModel {
PartyRoomHomeUIModel partyRoomHomeUIModel;
PartyRoomChatUIModel(this.partyRoomHomeUIModel);
RoomData? selectRoom;
RoomData? serverResultRoomData;
ResponseStream<RoomUpdateMessage>? roomStream;
Map<String, RoomUserData>? playersMap;
setRoom(RoomData? selectRoom) {
if (this.selectRoom == null) {
this.selectRoom = selectRoom;
notifyListeners();
loadRoom();
}
notifyListeners();
}
final playerStatusMap = {
RoomUserStatus.RoomUserStatusJoin: "在线",
RoomUserStatus.RoomUserStatusLostOffline: "离线",
RoomUserStatus.RoomUserStatusLeave: "已离开",
RoomUserStatus.RoomUserStatusWaitingConnect: "正在连接...",
};
onClose() async {
final ok = await showConfirmDialogs(
context!, "确认离开房间?", const Text("离开房间后,您的位置将被释放。"));
if (ok == true) {
partyRoomHomeUIModel.pageCtrl.animateToPage(0,
duration: const Duration(milliseconds: 130),
curve: Curves.easeInOutSine);
disposeRoom();
}
}
loadRoom() async {
if (selectRoom == null) return;
final userName = await globalUIModel.getRunningGameUser();
if (userName == null) return;
roomStream = PartyRoomGrpcServer.joinRoom(
selectRoom!.id, userName, AppConf.deviceUUID);
roomStream!.listen((value) {
dPrint("PartyRoomChatUIModel.roomStream.listen === $value");
if (value.roomUpdateType == RoomUpdateType.RoomClose) {
} else if (value.roomUpdateType == RoomUpdateType.RoomUpdateData) {
if (value.hasRoomData()) {
serverResultRoomData = value.roomData;
}
if (value.usersData.isNotEmpty) {
_updatePlayerList(value.usersData);
}
notifyListeners();
}
})
..onError((err) {
// showToast(context!, "连接到服务器出现错误:$err");
dPrint("PartyRoomChatUIModel.roomStream onError $err");
})
..onDone(() {
// showToast(context!, "房间已关闭");
dPrint("PartyRoomChatUIModel.roomStream onDone");
});
}
disposeRoom() {
selectRoom = null;
roomStream?.cancel();
roomStream = null;
notifyListeners();
}
void _updatePlayerList(List<RoomUserData> usersData) {
playersMap ??= {};
for (var element in usersData) {
playersMap![element.playerName] = element;
}
notifyListeners();
}
}

View File

@ -4,13 +4,40 @@ import 'dart:ui';
import 'package:extended_image/extended_image.dart'; import 'package:extended_image/extended_image.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_tilt/flutter_tilt.dart';
import 'package:starcitizen_doctor/base/ui.dart'; import 'package:starcitizen_doctor/base/ui.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/ui/party_room/party_room_chat_ui.dart';
import 'package:starcitizen_doctor/ui/party_room/party_room_chat_ui_model.dart';
import 'package:starcitizen_doctor/widgets/cache_image.dart'; import 'package:starcitizen_doctor/widgets/cache_image.dart';
import 'party_room_home_ui_model.dart'; import 'party_room_home_ui_model.dart';
class PartyRoomHomeUI extends BaseUI<PartyRoomHomeUIModel> { class PartyRoomHomeUI extends BaseUI<PartyRoomHomeUIModel> {
@override
void initState() {
Future.delayed(const Duration(milliseconds: 16)).then((_) {
ref.watch(provider).checkUIInit();
});
super.initState();
}
@override
Widget build(BuildContext context) {
final model = ref.watch(provider);
return PageView(
controller: model.pageCtrl,
physics: const NeverScrollableScrollPhysics(),
children: [
super.build(context),
BaseUIContainer(
uiCreate: () => PartyRoomChatUI(),
modelCreate: () =>
model.getChildUIModelProviders<PartyRoomChatUIModel>("chat"))
],
);
}
@override @override
Widget? buildBody(BuildContext context, PartyRoomHomeUIModel model) { Widget? buildBody(BuildContext context, PartyRoomHomeUIModel model) {
if (model.pingServerMessage == null) return makeLoading(context); if (model.pingServerMessage == null) return makeLoading(context);
@ -40,99 +67,7 @@ class PartyRoomHomeUI extends BaseUI<PartyRoomHomeUIModel> {
crossAxisSpacing: 24, crossAxisSpacing: 24,
itemCount: model.rooms!.length, itemCount: model.rooms!.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = model.rooms![index]; return makeRoomItemWidget(context, model, index);
final itemType = model.roomTypes?[item.roomTypeID];
final itemSubTypes = {
for (var t in itemType?.subTypes ?? <RoomSubtype>[]) 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),
],
),
)
],
),
),
),
),
),
);
}, },
), ),
), ),
@ -141,6 +76,105 @@ class PartyRoomHomeUI extends BaseUI<PartyRoomHomeUIModel> {
); );
} }
Widget makeRoomItemWidget(
BuildContext context,
PartyRoomHomeUIModel model,
int index,
) {
final item = model.rooms![index];
final itemType = model.roomTypes?[item.roomTypeID];
final itemSubTypes = {
for (var t in itemType?.subTypes ?? <RoomSubtype>[]) t.id: t
};
final createTime =
DateTime.fromMillisecondsSinceEpoch(item.createTime.toInt());
return Tilt(
borderRadius: BorderRadius.circular(13),
child: 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: GestureDetector(
onTap: () => model.onTapRoom(item),
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} / ${item.maxPlayer}"),
makeItemRow("创建时间:", "${createTime.toLocal()}"),
],
),
),
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, Widget makeSubTypeTag(String id, PartyRoomHomeUIModel model,
Map<String, RoomSubtype> itemSubTypes) { Map<String, RoomSubtype> itemSubTypes) {
final name = itemSubTypes[id]?.name ?? id; final name = itemSubTypes[id]?.name ?? id;

View File

@ -1,10 +1,13 @@
import 'package:fixnum/fixnum.dart'; 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/common/conf.dart';
import 'package:starcitizen_doctor/common/grpc/party_room_server.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/global_ui_model.dart';
import 'package:starcitizen_doctor/ui/party_room/dialogs/party_room_create_dialog_ui_model.dart'; import 'package:starcitizen_doctor/ui/party_room/dialogs/party_room_create_dialog_ui_model.dart';
import 'dialogs/party_room_create_dialog_ui.dart'; import 'dialogs/party_room_create_dialog_ui.dart';
import 'party_room_chat_ui_model.dart';
class PartyRoomHomeUIModel extends BaseUIModel { class PartyRoomHomeUIModel extends BaseUIModel {
String? pingServerMessage; String? pingServerMessage;
@ -40,10 +43,22 @@ class PartyRoomHomeUIModel extends BaseUIModel {
List<RoomData>? rooms; List<RoomData>? rooms;
final pageCtrl = PageController();
@override @override
void initModel() { void initModel() {
super.initModel(); super.initModel();
_loadTypes(); _loadTypes();
_touchUser();
}
@override
BaseUIModel? onCreateChildUIModel(modelKey) {
switch (modelKey) {
case "chat":
return PartyRoomChatUIModel(this);
}
return null;
} }
@override @override
@ -61,6 +76,7 @@ class PartyRoomHomeUIModel extends BaseUIModel {
pageNum = 0; pageNum = 0;
rooms = null; rooms = null;
notifyListeners(); notifyListeners();
_touchUser();
return super.reloadData(); return super.reloadData();
} }
@ -167,4 +183,33 @@ class PartyRoomHomeUIModel extends BaseUIModel {
onRefreshRoom() { onRefreshRoom() {
reloadData(); reloadData();
} }
Future<void> _touchUser() async {
if (getCreatedChildUIModel<PartyRoomChatUIModel>("chat")?.selectRoom ==
null) {
final userName = await globalUIModel.getRunningGameUser();
if (userName == null) return;
//
final room = await handleError(() =>
PartyRoomGrpcServer.touchUserRoom(userName, AppConf.deviceUUID));
dPrint("touch room == ${room?.toProto3Json()}");
if (room == null || room.id == "") return;
onTapRoom(room);
}
}
onTapRoom(RoomData item) {
getCreatedChildUIModel<PartyRoomChatUIModel>("chat", create: true)
?.setRoom(item);
notifyListeners();
pageCtrl.animateToPage(1,
duration: const Duration(milliseconds: 100), curve: Curves.easeInExpo);
}
void checkUIInit() {
if (getCreatedChildUIModel<PartyRoomChatUIModel>("chat")?.selectRoom !=
null) {
pageCtrl.jumpToPage(1);
}
}
} }