mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-02-06 23:20:21 +00:00
feat: PartyRoomGameLogTrackerProvider
This commit is contained in:
@@ -105,6 +105,12 @@ class PartyRoomUIModel extends _$PartyRoomUIModel {
|
||||
playTime: currentGameStartTime != gameStartTime ? gameStartTime : null,
|
||||
);
|
||||
}
|
||||
|
||||
if (next.deathEvents?.isNotEmpty ?? false) {
|
||||
for (final event in next.deathEvents!) {
|
||||
ref.read(partyRoomProvider.notifier).sendSignal("special_death", params: {"location": event.$1, "area": event.$2});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理连接状态变化
|
||||
|
||||
@@ -41,7 +41,7 @@ final class PartyRoomUIModelProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$partyRoomUIModelHash() => r'a0b6c3632ff33f2d58882f9bc1ab58c69c2487f4';
|
||||
String _$partyRoomUIModelHash() => r'add4703c9129465718a7850ea09025aa1ff35358';
|
||||
|
||||
abstract class _$PartyRoomUIModel extends $Notifier<PartyRoomUIState> {
|
||||
PartyRoomUIState build();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
@@ -18,8 +19,7 @@ sealed class PartyRoomGameLogTrackerProviderState with _$PartyRoomGameLogTracker
|
||||
@Default(0) int kills,
|
||||
@Default(0) int deaths,
|
||||
DateTime? gameStartTime,
|
||||
@Default([]) List<String> killedIds, // 本次迭代新增的击杀ID
|
||||
@Default([]) List<String> deathIds, // 本次迭代新增的死亡ID
|
||||
List<(String, String)>? deathEvents,
|
||||
}) = _PartyRoomGameLogTrackerProviderState;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ class PartyRoomGameLogTrackerProvider extends _$PartyRoomGameLogTrackerProvider
|
||||
|
||||
@override
|
||||
PartyRoomGameLogTrackerProviderState build({required DateTime startTime}) {
|
||||
startTime = DateTime.now();
|
||||
dPrint("[PartyRoomGameLogTrackerProvider] init $startTime");
|
||||
ref.onDispose(() {
|
||||
_disposed = true;
|
||||
@@ -65,16 +66,9 @@ class PartyRoomGameLogTrackerProvider extends _$PartyRoomGameLogTrackerProvider
|
||||
}
|
||||
} catch (e) {
|
||||
// 游戏未启动或发生错误
|
||||
state = state.copyWith(
|
||||
location: '<游戏未启动>',
|
||||
gameStartTime: null,
|
||||
kills: 0,
|
||||
deaths: 0,
|
||||
killedIds: [],
|
||||
deathIds: [],
|
||||
);
|
||||
state = state.copyWith(location: '<游戏未启动>', gameStartTime: null, kills: 0, deaths: 0);
|
||||
}
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +84,7 @@ class PartyRoomGameLogTrackerProvider extends _$PartyRoomGameLogTrackerProvider
|
||||
// 从统计数据中直接获取最新位置(全量查找的结果)
|
||||
final location = statistics.latestLocation == null ? '<主菜单>' : '[${statistics.latestLocation}]';
|
||||
|
||||
// 计算基于 _lastQueryTime 之后的增量 ID
|
||||
final newKilledIds = <String>[];
|
||||
final newDeathIds = <String>[];
|
||||
List<(String, String)> deathEvents = [];
|
||||
|
||||
if (_lastQueryTime != null) {
|
||||
// 遍历所有 actor_death 事件
|
||||
@@ -125,24 +117,15 @@ class PartyRoomGameLogTrackerProvider extends _$PartyRoomGameLogTrackerProvider
|
||||
}
|
||||
}
|
||||
|
||||
// 使用格式化字段,不再重新解析
|
||||
final victimId = data.victimId;
|
||||
final killerId = data.killerId;
|
||||
|
||||
if (victimId != null && killerId != null && victimId != killerId) {
|
||||
// 如果玩家是击杀者,记录被击杀的ID
|
||||
if (killerId == statistics.playerName) {
|
||||
newKilledIds.add(victimId);
|
||||
}
|
||||
|
||||
// 如果玩家是受害者,记录击杀者ID
|
||||
if (victimId == statistics.playerName) {
|
||||
newDeathIds.add(killerId);
|
||||
}
|
||||
if (data.playerName == data.victimId) {
|
||||
// 玩家死亡,增加记录
|
||||
deathEvents.add((data.location ?? "-", data.area ?? "-"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// debugPrint(
|
||||
// "[PartyRoomGameLogTrackerProvider] location $location killCount ${statistics.killCount} deathCount ${statistics.deathCount}",
|
||||
// );
|
||||
// 更新状态,只存储本次迭代的增量数据
|
||||
state = state.copyWith(
|
||||
location: location,
|
||||
@@ -151,10 +134,7 @@ class PartyRoomGameLogTrackerProvider extends _$PartyRoomGameLogTrackerProvider
|
||||
deaths: statistics.deathCount,
|
||||
// 从 startTime 开始的总计数
|
||||
gameStartTime: statistics.gameStartTime,
|
||||
// 全量查找的游戏开始时间
|
||||
killedIds: newKilledIds,
|
||||
// 只存储本次迭代的增量
|
||||
deathIds: newDeathIds, // 只存储本次迭代的增量
|
||||
deathEvents: deathEvents,
|
||||
);
|
||||
|
||||
// 更新查询时间为本次查询的时刻
|
||||
|
||||
@@ -12,10 +12,9 @@ part of 'game_log_tracker_provider.dart';
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$PartyRoomGameLogTrackerProviderState {
|
||||
mixin _$PartyRoomGameLogTrackerProviderState implements DiagnosticableTreeMixin {
|
||||
|
||||
String get location; int get kills; int get deaths; DateTime? get gameStartTime; List<String> get killedIds;// 本次迭代新增的击杀ID
|
||||
List<String> get deathIds;
|
||||
String get location; int get kills; int get deaths; DateTime? get gameStartTime; List<(String, String)>? get deathEvents;
|
||||
/// Create a copy of PartyRoomGameLogTrackerProviderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -23,19 +22,25 @@ mixin _$PartyRoomGameLogTrackerProviderState {
|
||||
$PartyRoomGameLogTrackerProviderStateCopyWith<PartyRoomGameLogTrackerProviderState> get copyWith => _$PartyRoomGameLogTrackerProviderStateCopyWithImpl<PartyRoomGameLogTrackerProviderState>(this as PartyRoomGameLogTrackerProviderState, _$identity);
|
||||
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'PartyRoomGameLogTrackerProviderState'))
|
||||
..add(DiagnosticsProperty('location', location))..add(DiagnosticsProperty('kills', kills))..add(DiagnosticsProperty('deaths', deaths))..add(DiagnosticsProperty('gameStartTime', gameStartTime))..add(DiagnosticsProperty('deathEvents', deathEvents));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PartyRoomGameLogTrackerProviderState&&(identical(other.location, location) || other.location == location)&&(identical(other.kills, kills) || other.kills == kills)&&(identical(other.deaths, deaths) || other.deaths == deaths)&&(identical(other.gameStartTime, gameStartTime) || other.gameStartTime == gameStartTime)&&const DeepCollectionEquality().equals(other.killedIds, killedIds)&&const DeepCollectionEquality().equals(other.deathIds, deathIds));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PartyRoomGameLogTrackerProviderState&&(identical(other.location, location) || other.location == location)&&(identical(other.kills, kills) || other.kills == kills)&&(identical(other.deaths, deaths) || other.deaths == deaths)&&(identical(other.gameStartTime, gameStartTime) || other.gameStartTime == gameStartTime)&&const DeepCollectionEquality().equals(other.deathEvents, deathEvents));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,location,kills,deaths,gameStartTime,const DeepCollectionEquality().hash(killedIds),const DeepCollectionEquality().hash(deathIds));
|
||||
int get hashCode => Object.hash(runtimeType,location,kills,deaths,gameStartTime,const DeepCollectionEquality().hash(deathEvents));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PartyRoomGameLogTrackerProviderState(location: $location, kills: $kills, deaths: $deaths, gameStartTime: $gameStartTime, killedIds: $killedIds, deathIds: $deathIds)';
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'PartyRoomGameLogTrackerProviderState(location: $location, kills: $kills, deaths: $deaths, gameStartTime: $gameStartTime, deathEvents: $deathEvents)';
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +51,7 @@ abstract mixin class $PartyRoomGameLogTrackerProviderStateCopyWith<$Res> {
|
||||
factory $PartyRoomGameLogTrackerProviderStateCopyWith(PartyRoomGameLogTrackerProviderState value, $Res Function(PartyRoomGameLogTrackerProviderState) _then) = _$PartyRoomGameLogTrackerProviderStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String location, int kills, int deaths, DateTime? gameStartTime, List<String> killedIds, List<String> deathIds
|
||||
String location, int kills, int deaths, DateTime? gameStartTime, List<(String, String)>? deathEvents
|
||||
});
|
||||
|
||||
|
||||
@@ -63,15 +68,14 @@ class _$PartyRoomGameLogTrackerProviderStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PartyRoomGameLogTrackerProviderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? location = null,Object? kills = null,Object? deaths = null,Object? gameStartTime = freezed,Object? killedIds = null,Object? deathIds = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? location = null,Object? kills = null,Object? deaths = null,Object? gameStartTime = freezed,Object? deathEvents = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
location: null == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
|
||||
as String,kills: null == kills ? _self.kills : kills // ignore: cast_nullable_to_non_nullable
|
||||
as int,deaths: null == deaths ? _self.deaths : deaths // ignore: cast_nullable_to_non_nullable
|
||||
as int,gameStartTime: freezed == gameStartTime ? _self.gameStartTime : gameStartTime // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,killedIds: null == killedIds ? _self.killedIds : killedIds // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,deathIds: null == deathIds ? _self.deathIds : deathIds // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
as DateTime?,deathEvents: freezed == deathEvents ? _self.deathEvents : deathEvents // ignore: cast_nullable_to_non_nullable
|
||||
as List<(String, String)>?,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -153,10 +157,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String location, int kills, int deaths, DateTime? gameStartTime, List<String> killedIds, List<String> deathIds)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String location, int kills, int deaths, DateTime? gameStartTime, List<(String, String)>? deathEvents)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PartyRoomGameLogTrackerProviderState() when $default != null:
|
||||
return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_that.killedIds,_that.deathIds);case _:
|
||||
return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_that.deathEvents);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -174,10 +178,10 @@ return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_tha
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String location, int kills, int deaths, DateTime? gameStartTime, List<String> killedIds, List<String> deathIds) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String location, int kills, int deaths, DateTime? gameStartTime, List<(String, String)>? deathEvents) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PartyRoomGameLogTrackerProviderState():
|
||||
return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_that.killedIds,_that.deathIds);}
|
||||
return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_that.deathEvents);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -191,10 +195,10 @@ return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_tha
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String location, int kills, int deaths, DateTime? gameStartTime, List<String> killedIds, List<String> deathIds)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String location, int kills, int deaths, DateTime? gameStartTime, List<(String, String)>? deathEvents)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PartyRoomGameLogTrackerProviderState() when $default != null:
|
||||
return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_that.killedIds,_that.deathIds);case _:
|
||||
return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_that.deathEvents);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -205,28 +209,21 @@ return $default(_that.location,_that.kills,_that.deaths,_that.gameStartTime,_tha
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _PartyRoomGameLogTrackerProviderState implements PartyRoomGameLogTrackerProviderState {
|
||||
const _PartyRoomGameLogTrackerProviderState({this.location = '', this.kills = 0, this.deaths = 0, this.gameStartTime, final List<String> killedIds = const [], final List<String> deathIds = const []}): _killedIds = killedIds,_deathIds = deathIds;
|
||||
class _PartyRoomGameLogTrackerProviderState with DiagnosticableTreeMixin implements PartyRoomGameLogTrackerProviderState {
|
||||
const _PartyRoomGameLogTrackerProviderState({this.location = '', this.kills = 0, this.deaths = 0, this.gameStartTime, final List<(String, String)>? deathEvents}): _deathEvents = deathEvents;
|
||||
|
||||
|
||||
@override@JsonKey() final String location;
|
||||
@override@JsonKey() final int kills;
|
||||
@override@JsonKey() final int deaths;
|
||||
@override final DateTime? gameStartTime;
|
||||
final List<String> _killedIds;
|
||||
@override@JsonKey() List<String> get killedIds {
|
||||
if (_killedIds is EqualUnmodifiableListView) return _killedIds;
|
||||
final List<(String, String)>? _deathEvents;
|
||||
@override List<(String, String)>? get deathEvents {
|
||||
final value = _deathEvents;
|
||||
if (value == null) return null;
|
||||
if (_deathEvents is EqualUnmodifiableListView) return _deathEvents;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_killedIds);
|
||||
}
|
||||
|
||||
// 本次迭代新增的击杀ID
|
||||
final List<String> _deathIds;
|
||||
// 本次迭代新增的击杀ID
|
||||
@override@JsonKey() List<String> get deathIds {
|
||||
if (_deathIds is EqualUnmodifiableListView) return _deathIds;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_deathIds);
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -237,19 +234,25 @@ class _PartyRoomGameLogTrackerProviderState implements PartyRoomGameLogTrackerPr
|
||||
_$PartyRoomGameLogTrackerProviderStateCopyWith<_PartyRoomGameLogTrackerProviderState> get copyWith => __$PartyRoomGameLogTrackerProviderStateCopyWithImpl<_PartyRoomGameLogTrackerProviderState>(this, _$identity);
|
||||
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'PartyRoomGameLogTrackerProviderState'))
|
||||
..add(DiagnosticsProperty('location', location))..add(DiagnosticsProperty('kills', kills))..add(DiagnosticsProperty('deaths', deaths))..add(DiagnosticsProperty('gameStartTime', gameStartTime))..add(DiagnosticsProperty('deathEvents', deathEvents));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PartyRoomGameLogTrackerProviderState&&(identical(other.location, location) || other.location == location)&&(identical(other.kills, kills) || other.kills == kills)&&(identical(other.deaths, deaths) || other.deaths == deaths)&&(identical(other.gameStartTime, gameStartTime) || other.gameStartTime == gameStartTime)&&const DeepCollectionEquality().equals(other._killedIds, _killedIds)&&const DeepCollectionEquality().equals(other._deathIds, _deathIds));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PartyRoomGameLogTrackerProviderState&&(identical(other.location, location) || other.location == location)&&(identical(other.kills, kills) || other.kills == kills)&&(identical(other.deaths, deaths) || other.deaths == deaths)&&(identical(other.gameStartTime, gameStartTime) || other.gameStartTime == gameStartTime)&&const DeepCollectionEquality().equals(other._deathEvents, _deathEvents));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,location,kills,deaths,gameStartTime,const DeepCollectionEquality().hash(_killedIds),const DeepCollectionEquality().hash(_deathIds));
|
||||
int get hashCode => Object.hash(runtimeType,location,kills,deaths,gameStartTime,const DeepCollectionEquality().hash(_deathEvents));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PartyRoomGameLogTrackerProviderState(location: $location, kills: $kills, deaths: $deaths, gameStartTime: $gameStartTime, killedIds: $killedIds, deathIds: $deathIds)';
|
||||
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
|
||||
return 'PartyRoomGameLogTrackerProviderState(location: $location, kills: $kills, deaths: $deaths, gameStartTime: $gameStartTime, deathEvents: $deathEvents)';
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +263,7 @@ abstract mixin class _$PartyRoomGameLogTrackerProviderStateCopyWith<$Res> implem
|
||||
factory _$PartyRoomGameLogTrackerProviderStateCopyWith(_PartyRoomGameLogTrackerProviderState value, $Res Function(_PartyRoomGameLogTrackerProviderState) _then) = __$PartyRoomGameLogTrackerProviderStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String location, int kills, int deaths, DateTime? gameStartTime, List<String> killedIds, List<String> deathIds
|
||||
String location, int kills, int deaths, DateTime? gameStartTime, List<(String, String)>? deathEvents
|
||||
});
|
||||
|
||||
|
||||
@@ -277,15 +280,14 @@ class __$PartyRoomGameLogTrackerProviderStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PartyRoomGameLogTrackerProviderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? location = null,Object? kills = null,Object? deaths = null,Object? gameStartTime = freezed,Object? killedIds = null,Object? deathIds = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? location = null,Object? kills = null,Object? deaths = null,Object? gameStartTime = freezed,Object? deathEvents = freezed,}) {
|
||||
return _then(_PartyRoomGameLogTrackerProviderState(
|
||||
location: null == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
|
||||
as String,kills: null == kills ? _self.kills : kills // ignore: cast_nullable_to_non_nullable
|
||||
as int,deaths: null == deaths ? _self.deaths : deaths // ignore: cast_nullable_to_non_nullable
|
||||
as int,gameStartTime: freezed == gameStartTime ? _self.gameStartTime : gameStartTime // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,killedIds: null == killedIds ? _self._killedIds : killedIds // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,deathIds: null == deathIds ? _self._deathIds : deathIds // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
as DateTime?,deathEvents: freezed == deathEvents ? _self._deathEvents : deathEvents // ignore: cast_nullable_to_non_nullable
|
||||
as List<(String, String)>?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ final class PartyRoomGameLogTrackerProviderProvider
|
||||
}
|
||||
|
||||
String _$partyRoomGameLogTrackerProviderHash() =>
|
||||
r'ecb015eb46d25bfe11bbb153242fd5c4f20ef367';
|
||||
r'3e1560b2fffc5461a41bece57b43e27f4112ad0c';
|
||||
|
||||
final class PartyRoomGameLogTrackerProviderFamily extends $Family
|
||||
with
|
||||
|
||||
@@ -97,15 +97,12 @@ class PartyRoomMemberItem extends ConsumerWidget {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
member.status.currentLocation.isNotEmpty ? member.status.currentLocation : '...',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .9)),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
"K: ${member.status.kills} D: ${member.status.deaths}",
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)),
|
||||
Expanded(
|
||||
child: Text(
|
||||
member.status.currentLocation.isNotEmpty ? member.status.currentLocation : '...',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .9)),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -210,6 +210,11 @@ class _MessageItem extends ConsumerWidget {
|
||||
final userName = _getEventUserName(roomEvent);
|
||||
final avatarUrl = _getEventAvatarUrl(roomEvent);
|
||||
|
||||
// 检查是否是死亡信号,显示特殊卡片
|
||||
if (isSignal && roomEvent.signalId == 'special_death') {
|
||||
return _buildDeathMessageCard(context, roomEvent, userName, avatarUrl);
|
||||
}
|
||||
|
||||
final text = _getEventText(roomEvent, ref);
|
||||
if (text == null) return const SizedBox.shrink();
|
||||
|
||||
@@ -259,6 +264,104 @@ class _MessageItem extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDeathMessageCard(
|
||||
BuildContext context,
|
||||
partroom.RoomEvent roomEvent,
|
||||
String userName,
|
||||
String? avatarUrl,
|
||||
) {
|
||||
final location = roomEvent.signalParams['location'] ?? '未知位置';
|
||||
final area = roomEvent.signalParams['area'] ?? '未知区域';
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildUserAvatar(userName, avatarUrl: avatarUrl, size: 28),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 用户名和时间
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
userName,
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
_formatTime(roomEvent.timestamp),
|
||||
style: const TextStyle(fontSize: 11, color: Color(0xFF80848E)),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// 死亡卡片
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF2B2D31),
|
||||
border: Border.all(color: const Color(0xFFED4245).withValues(alpha: 0.3)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 标题
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFED4245).withValues(alpha: 0.2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(FluentIcons.status_error_full, size: 14, color: Color(0xFFED4245)),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'玩家死亡',
|
||||
style: TextStyle(fontSize: 14, color: Color(0xFFED4245), fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 位置信息
|
||||
_buildInfoRow(icon: FluentIcons.location, label: '位置', value: location),
|
||||
const SizedBox(height: 8),
|
||||
// 区域信息
|
||||
_buildInfoRow(icon: FluentIcons.map_pin, label: '区域', value: area),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoRow({required IconData icon, required String label, required String value}) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, size: 14, color: Colors.white.withValues(alpha: .4)),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'$label: ',
|
||||
style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .4), fontWeight: FontWeight.w500),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(value, style: const TextStyle(fontSize: 13, color: Color(0xFFDBDEE1))),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String _getEventUserName(partroom.RoomEvent event) {
|
||||
switch (event.type) {
|
||||
case partroom.RoomEventType.SIGNAL_BROADCAST:
|
||||
|
||||
@@ -123,7 +123,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
? const Color(0xFF4CAF50)
|
||||
: isActive
|
||||
? const Color(0xFF4A9EFF)
|
||||
: Colors.grey.withValues(alpha: 0.3),
|
||||
: Colors.white.withValues(alpha: 0.4),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
@@ -143,7 +143,7 @@ class PartyRoomRegisterPage extends HookConsumerWidget {
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: isActive ? const Color(0xFF4A9EFF) : Colors.grey.withValues(alpha: 0.7),
|
||||
color: isActive ? const Color(0xFF4A9EFF) : Colors.white.withValues(alpha: 0.4),
|
||||
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user