Files
front-hokm/lib/feature/game/presentation/bloc/game_state.dart
T

125 lines
3.8 KiB
Dart

import 'package:equatable/equatable.dart';
import '../../../../core/network/ws_client.dart';
import '../../domain/entities/game_entities.dart';
/// یک بازیکن در اتاق انتظارِ میز خصوصی.
class LobbyPlayer {
final String name;
final bool host;
final int seat; // جایگاهِ مطلق (۰..۳)
const LobbyPlayer(this.name, this.host, this.seat);
}
/// وضعیت اتاق انتظارِ میز خصوصی (دورهمی).
class TableLobby {
final String code;
final List<LobbyPlayer> players;
final bool isHost;
final int youSeat; // جایگاهِ مطلقِ خودِ کاربر (برای چیدمانِ صحنه)
final int remaining;
final bool unlimited;
final int stake; // شرطِ سکه‌ایِ هر بازیکن (۰ یعنی رایگان)
const TableLobby({
required this.code,
required this.players,
required this.isHost,
required this.youSeat,
required this.remaining,
required this.unlimited,
required this.stake,
});
factory TableLobby.fromJson(Map<String, dynamic> j) => TableLobby(
code: (j['code'] ?? '') as String,
players: ((j['players'] as List?) ?? [])
.map((e) => LobbyPlayer(
(e['name'] ?? '') as String,
(e['host'] ?? false) as bool,
(e['seat'] ?? 0) as int,
))
.toList(),
isHost: (j['host'] ?? false) as bool,
youSeat: (j['you_seat'] ?? 0) as int,
remaining: (j['remaining'] ?? 0) as int,
unlimited: (j['unlimited'] ?? false) as bool,
stake: (j['stake'] ?? 0) as int,
);
String get sig => '$code|$isHost|$youSeat|$remaining|$unlimited|$stake|'
'${players.map((p) => '${p.name}${p.host ? '*' : ''}@${p.seat}').join(',')}';
}
/// حبابِ پیام/شکلکِ یک بازیکن که کنارِ آواتارش نشان داده می‌شود.
/// id برای انقضای دقیق (پاک‌کردنِ همین حباب و نه حبابِ جدیدتر) به‌کار می‌رود.
class ChatBubble {
final String? text;
final String? emoji;
final int id;
const ChatBubble({this.text, this.emoji, required this.id});
}
class GameUiState extends Equatable {
final WsStatus connection;
final GameState? state;
final HandResult? handResult;
final GameOver? gameOver;
final String? notice;
final TableLobby? lobby;
final int? countdown;
final bool tableClosed;
final Map<int, ChatBubble> chatBubbles; // جایگاه ⇒ حبابِ پیامِ فعال
const GameUiState({
this.connection = WsStatus.connecting,
this.state,
this.handResult,
this.gameOver,
this.notice,
this.lobby,
this.countdown,
this.tableClosed = false,
this.chatBubbles = const {},
});
GameUiState copyWith({
WsStatus? connection,
GameState? state,
HandResult? handResult,
GameOver? gameOver,
String? notice,
TableLobby? lobby,
int? countdown,
bool? tableClosed,
Map<int, ChatBubble>? chatBubbles,
bool clearHandResult = false,
bool clearNotice = false,
}) =>
GameUiState(
connection: connection ?? this.connection,
state: state ?? this.state,
handResult: clearHandResult ? null : (handResult ?? this.handResult),
gameOver: gameOver ?? this.gameOver,
notice: clearNotice ? null : (notice ?? this.notice),
lobby: lobby ?? this.lobby,
countdown: countdown ?? this.countdown,
tableClosed: tableClosed ?? this.tableClosed,
chatBubbles: chatBubbles ?? this.chatBubbles,
);
@override
List<Object?> get props => [
connection,
state,
handResult,
gameOver,
notice,
lobby?.sig,
countdown,
tableClosed,
chatBubbles.entries
.map((e) => '${e.key}:${e.value.id}')
.join(','),
];
}