diff --git a/lib/base/ui_model.dart b/lib/base/ui_model.dart index 8ebc002..fadb55a 100644 --- a/lib/base/ui_model.dart +++ b/lib/base/ui_model.dart @@ -64,7 +64,7 @@ class BaseUIModel extends ChangeNotifier { dPrint("$runtimeType.handleError Error:$e"); String errorMsg = "Unknown Error"; if (e is GrpcError) { - errorMsg = "服务器错误: ${e.message} ?? Unknown Error"; + errorMsg = "远程服务器消息: ${e.message ?? "Unknown Error"}"; } else { errorMsg = e.toString(); } @@ -112,7 +112,10 @@ class BaseUIModel extends ChangeNotifier { return _childUIProviders![modelKey]!; } - T? getCreatedChildUIModel(String modelKey) { + T? getCreatedChildUIModel(String modelKey,{bool create = false}) { + if (create && _childUIModels?[modelKey] == null) { + _getChildUIModel(modelKey); + } return _childUIModels?[modelKey] as T?; } diff --git a/lib/grpc/party_room_server.dart b/lib/common/grpc/party_room_server.dart similarity index 73% rename from lib/grpc/party_room_server.dart rename to lib/common/grpc/party_room_server.dart index a5a22ce..9189cdf 100644 --- a/lib/grpc/party_room_server.dart +++ b/lib/common/grpc/party_room_server.dart @@ -34,4 +34,15 @@ class PartyRoomGrpcServer { static Future createRoom(RoomData roomData) async { return await _indexService.createRoom(roomData); } + + static Future touchUserRoom(String userName, String deviceUUID) { + return _indexService + .touchUser(PreUser(userName: userName, deviceUUID: deviceUUID)); + } + + static ResponseStream joinRoom( + String roomID, String userName, String deviceUUID) { + return _indexService.joinRoom( + PreUser(roomID: roomID, userName: userName, deviceUUID: deviceUUID)); + } } diff --git a/lib/generated/grpc/party_room_server/chat.pb.dart b/lib/generated/grpc/party_room_server/chat.pb.dart new file mode 100644 index 0000000..18bfa18 --- /dev/null +++ b/lib/generated/grpc/party_room_server/chat.pb.dart @@ -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(3, _omitFieldNames ? '' : 'receiverType', $pb.PbFieldType.OE, protoName: 'receiverType', defaultOrMaker: ReceiverType.RoomMsg, valueOf: ReceiverType.valueOf, enumValues: ReceiverType.values) + ..e(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 createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ChatMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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'); diff --git a/lib/generated/grpc/party_room_server/chat.pbenum.dart b/lib/generated/grpc/party_room_server/chat.pbenum.dart new file mode 100644 index 0000000..181917c --- /dev/null +++ b/lib/generated/grpc/party_room_server/chat.pbenum.dart @@ -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 values = [ + 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 values = [ + 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'); diff --git a/lib/generated/grpc/party_room_server/chat.pbgrpc.dart b/lib/generated/grpc/party_room_server/chat.pbgrpc.dart new file mode 100644 index 0000000..e3c9cce --- /dev/null +++ b/lib/generated/grpc/party_room_server/chat.pbgrpc.dart @@ -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); +} diff --git a/lib/generated/grpc/party_room_server/chat.pbjson.dart b/lib/generated/grpc/party_room_server/chat.pbjson.dart new file mode 100644 index 0000000..cd79d50 --- /dev/null +++ b/lib/generated/grpc/party_room_server/chat.pbjson.dart @@ -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'); + diff --git a/lib/generated/grpc/party_room_server/index.pb.dart b/lib/generated/grpc/party_room_server/index.pb.dart index 312e260..c8d6525 100644 --- a/lib/generated/grpc/party_room_server/index.pb.dart +++ b/lib/generated/grpc/party_room_server/index.pb.dart @@ -519,6 +519,7 @@ class RoomData extends $pb.GeneratedMessage { $core.String? deviceUUID, $core.String? announcement, $core.String? avatar, + $fixnum.Int64? updateTime, }) { final $result = create(); if (id != null) { @@ -554,6 +555,9 @@ class RoomData extends $pb.GeneratedMessage { if (avatar != null) { $result.avatar = avatar; } + if (updateTime != null) { + $result.updateTime = updateTime; + } return $result; } RoomData._() : super(); @@ -572,6 +576,7 @@ class RoomData extends $pb.GeneratedMessage { ..aOS(9, _omitFieldNames ? '' : 'deviceUUID', protoName: 'deviceUUID') ..aOS(10, _omitFieldNames ? '' : 'announcement') ..aOS(11, _omitFieldNames ? '' : 'avatar') + ..aInt64(12, _omitFieldNames ? '' : 'updateTime', protoName: 'updateTime') ..hasRequiredFields = false ; @@ -688,6 +693,15 @@ class RoomData extends $pb.GeneratedMessage { $core.bool hasAvatar() => $_has(10); @$pb.TagNumber(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 { @@ -856,6 +870,250 @@ class RoomListData extends $pb.GeneratedMessage { $core.List 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 createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static PreUser getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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(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 createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RoomUserData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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? 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(1, _omitFieldNames ? '' : 'roomData', protoName: 'roomData', subBuilder: RoomData.create) + ..pc(2, _omitFieldNames ? '' : 'usersData', $pb.PbFieldType.PM, protoName: 'usersData', subBuilder: RoomUserData.create) + ..e(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 createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RoomUpdateMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(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 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 _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/lib/generated/grpc/party_room_server/index.pbenum.dart b/lib/generated/grpc/party_room_server/index.pbenum.dart index b2147d1..bd7403a 100644 --- a/lib/generated/grpc/party_room_server/index.pbenum.dart +++ b/lib/generated/grpc/party_room_server/index.pbenum.dart @@ -59,5 +59,39 @@ class RoomSortType extends $pb.ProtobufEnum { 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 values = [ + 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 values = [ + 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'); diff --git a/lib/generated/grpc/party_room_server/index.pbgrpc.dart b/lib/generated/grpc/party_room_server/index.pbgrpc.dart index a89e4da..cb22f8f 100644 --- a/lib/generated/grpc/party_room_server/index.pbgrpc.dart +++ b/lib/generated/grpc/party_room_server/index.pbgrpc.dart @@ -37,6 +37,18 @@ class IndexServiceClient extends $grpc.Client { '/IndexService/GetRoomList', ($0.RoomListPageReqData value) => value.writeToBuffer(), ($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, {$grpc.CallOptions? options, @@ -59,6 +71,18 @@ class IndexServiceClient extends $grpc.Client { $grpc.ResponseFuture<$0.RoomListData> getRoomList($0.RoomListPageReqData request, {$grpc.CallOptions? 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') @@ -94,6 +118,27 @@ abstract class IndexServiceBase extends $grpc.Service { false, ($core.List<$core.int> value) => $0.RoomListPageReqData.fromBuffer(value), ($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 { @@ -112,8 +157,23 @@ abstract class IndexServiceBase extends $grpc.Service { 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.RoomTypesData> getRoomTypes($grpc.ServiceCall call, $0.Empty 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.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); } diff --git a/lib/generated/grpc/party_room_server/index.pbjson.dart b/lib/generated/grpc/party_room_server/index.pbjson.dart index 98d2736..5f2a4c6 100644 --- a/lib/generated/grpc/party_room_server/index.pbjson.dart +++ b/lib/generated/grpc/party_room_server/index.pbjson.dart @@ -50,6 +50,36 @@ final $typed_data.Uint8List roomSortTypeDescriptor = $convert.base64Decode( '5pbXVtUGxheWVyTnVtYmVyEAISEwoPUmVjZW50bHlDcmVhdGVkEAMSEQoNT2xkZXN0Q3JlYXRl' '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') const Empty$json = { '1': 'Empty', @@ -165,6 +195,7 @@ const RoomData$json = { {'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'}, + {'1': 'updateTime', '3': 12, '4': 1, '5': 3, '10': 'updateTime'}, ], }; @@ -176,7 +207,7 @@ final $typed_data.Uint8List roomDataDescriptor = $convert.base64Decode( 'ABKANSCmNyZWF0ZVRpbWUSHAoJY3VyUGxheWVyGAcgASgFUgljdXJQbGF5ZXISIwoGc3RhdHVz' 'GAggASgOMgsuUm9vbVN0YXR1c1IGc3RhdHVzEh4KCmRldmljZVVVSUQYCSABKAlSCmRldmljZV' 'VVSUQSIgoMYW5ub3VuY2VtZW50GAogASgJUgxhbm5vdW5jZW1lbnQSFgoGYXZhdGFyGAsgASgJ' - 'UgZhdmF0YXI='); + 'UgZhdmF0YXISHgoKdXBkYXRlVGltZRgMIAEoA1IKdXBkYXRlVGltZQ=='); @$core.Deprecated('Use roomListPageReqDataDescriptor instead') const RoomListPageReqData$json = { @@ -211,3 +242,51 @@ final $typed_data.Uint8List roomListDataDescriptor = $convert.base64Decode( 'CgxSb29tTGlzdERhdGESLQoIcGFnZURhdGEYASABKAsyES5CYXNlUGFnZVJlc3BEYXRhUghwYW' '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=='); + diff --git a/lib/global_ui_model.dart b/lib/global_ui_model.dart index 5d2065f..0502823 100644 --- a/lib/global_ui_model.dart +++ b/lib/global_ui_model.dart @@ -16,7 +16,7 @@ final globalUIModelProvider = ChangeNotifierProvider((ref) => globalUIModel); class AppGlobalUIModel extends BaseUIModel { Timer? activityThemeColorTimer; - Future getRunningGameUser() async { + Future getRunningGameUser() async { await Future.delayed(const Duration(milliseconds: 300)); ///TODO 实现获取运行中用户名 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 bb779ad..65c1a10 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 @@ -1,8 +1,8 @@ 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 'package:starcitizen_doctor/grpc/party_room_server.dart'; class PartyRoomCreateDialogUIModel extends BaseUIModel { Map roomTypes; diff --git a/lib/ui/party_room/party_room_chat_ui.dart b/lib/ui/party_room/party_room_chat_ui.dart new file mode 100644 index 0000000..91b7fe9 --- /dev/null +++ b/lib/ui/party_room/party_room_chat_ui.dart @@ -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 { + @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"; +} diff --git a/lib/ui/party_room/party_room_chat_ui_model.dart b/lib/ui/party_room/party_room_chat_ui_model.dart new file mode 100644 index 0000000..f418915 --- /dev/null +++ b/lib/ui/party_room/party_room_chat_ui_model.dart @@ -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? roomStream; + + Map? 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 usersData) { + playersMap ??= {}; + for (var element in usersData) { + playersMap![element.playerName] = element; + } + notifyListeners(); + } +} diff --git a/lib/ui/party_room/party_room_home_ui.dart b/lib/ui/party_room/party_room_home_ui.dart index 3e18398..a7f1921 100644 --- a/lib/ui/party_room/party_room_home_ui.dart +++ b/lib/ui/party_room/party_room_home_ui.dart @@ -4,13 +4,40 @@ import 'dart:ui'; import 'package:extended_image/extended_image.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/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 'party_room_home_ui_model.dart'; class PartyRoomHomeUI extends BaseUI { + @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("chat")) + ], + ); + } + @override Widget? buildBody(BuildContext context, PartyRoomHomeUIModel model) { if (model.pingServerMessage == null) return makeLoading(context); @@ -40,99 +67,7 @@ class PartyRoomHomeUI extends BaseUI { 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), - ], - ), - ) - ], - ), - ), - ), - ), - ), - ); + return makeRoomItemWidget(context, model, index); }, ), ), @@ -141,6 +76,105 @@ class PartyRoomHomeUI extends BaseUI { ); } + 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 ?? []) 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, Map itemSubTypes) { final name = itemSubTypes[id]?.name ?? id; 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 d080b00..9bd83ce 100644 --- a/lib/ui/party_room/party_room_home_ui_model.dart +++ b/lib/ui/party_room/party_room_home_ui_model.dart @@ -1,10 +1,13 @@ import 'package:fixnum/fixnum.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/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 'dialogs/party_room_create_dialog_ui.dart'; +import 'party_room_chat_ui_model.dart'; class PartyRoomHomeUIModel extends BaseUIModel { String? pingServerMessage; @@ -40,10 +43,22 @@ class PartyRoomHomeUIModel extends BaseUIModel { List? rooms; + final pageCtrl = PageController(); + @override void initModel() { super.initModel(); _loadTypes(); + _touchUser(); + } + + @override + BaseUIModel? onCreateChildUIModel(modelKey) { + switch (modelKey) { + case "chat": + return PartyRoomChatUIModel(this); + } + return null; } @override @@ -61,6 +76,7 @@ class PartyRoomHomeUIModel extends BaseUIModel { pageNum = 0; rooms = null; notifyListeners(); + _touchUser(); return super.reloadData(); } @@ -167,4 +183,33 @@ class PartyRoomHomeUIModel extends BaseUIModel { onRefreshRoom() { reloadData(); } + + Future _touchUser() async { + if (getCreatedChildUIModel("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("chat", create: true) + ?.setRoom(item); + notifyListeners(); + pageCtrl.animateToPage(1, + duration: const Duration(milliseconds: 100), curve: Curves.easeInExpo); + } + + void checkUIInit() { + if (getCreatedChildUIModel("chat")?.selectRoom != + null) { + pageCtrl.jumpToPage(1); + } + } }