feat: refactor code

This commit is contained in:
2026-06-17 12:57:28 +03:30
parent e9f294fa19
commit 519752b478
106 changed files with 3459 additions and 2309 deletions
@@ -0,0 +1,124 @@
// موجودیت‌های وضعیت بازی (نگاشت از پیام‌های WebSocket سرور).
class GamePlayer {
final int seat;
final String name;
final bool bot;
final bool connected;
GamePlayer.fromJson(Map<String, dynamic> j)
: seat = (j['seat'] ?? 0) as int,
name = (j['name'] ?? '') as String,
bot = (j['bot'] ?? false) as bool,
connected = (j['connected'] ?? false) as bool;
}
class TrickCard {
final int seat;
final String card;
TrickCard(this.seat, this.card);
factory TrickCard.fromJson(Map<String, dynamic> j) =>
TrickCard((j['seat'] ?? 0) as int, (j['card'] ?? '') as String);
}
/// نمای وضعیت بازی برای بازیکن جاری (پیام type=state).
class GameState {
final String room;
final String phase; // choose_trump | playing | hand_over | game_over
final int yourSeat;
final int hakem;
final int turn;
final String? trump;
final bool trickDone;
final List<String> yourHand;
final List<int> handCounts;
final List<TrickCard> trick;
final String? leadSuit;
final List<int> tricksWon;
final List<int> scores;
final int targetScore;
final List<GamePlayer> players;
GameState({
required this.room,
required this.phase,
required this.yourSeat,
required this.hakem,
required this.turn,
required this.trump,
required this.trickDone,
required this.yourHand,
required this.handCounts,
required this.trick,
required this.leadSuit,
required this.tricksWon,
required this.scores,
required this.targetScore,
required this.players,
});
factory GameState.fromJson(Map<String, dynamic> j) {
List<int> ints(dynamic v) =>
((v as List?) ?? []).map((e) => (e as num).toInt()).toList();
return GameState(
room: (j['room'] ?? '') as String,
phase: (j['phase'] ?? '') as String,
yourSeat: (j['your_seat'] ?? 0) as int,
hakem: (j['hakem'] ?? 0) as int,
turn: (j['turn'] ?? 0) as int,
trump: j['trump'] as String?,
trickDone: (j['trick_done'] ?? false) as bool,
yourHand:
((j['your_hand'] as List?) ?? []).map((e) => e as String).toList(),
handCounts: ints(j['hand_counts']),
trick: ((j['trick'] as List?) ?? [])
.map((e) => TrickCard.fromJson(Map<String, dynamic>.from(e as Map)))
.toList(),
leadSuit: j['lead_suit'] as String?,
tricksWon: ints(j['tricks_won']),
scores: ints(j['scores']),
targetScore: (j['target_score'] ?? 7) as int,
players: ((j['players'] as List?) ?? [])
.map((e) => GamePlayer.fromJson(Map<String, dynamic>.from(e as Map)))
.toList(),
);
}
bool get isMyTurn => turn == yourSeat;
bool get amHakem => hakem == yourSeat;
GamePlayer? playerAt(int seat) =>
players.where((p) => p.seat == seat).cast<GamePlayer?>().firstOrNull;
}
/// نتیجه‌ی یک هَند (پیام type=hand_over).
class HandResult {
final int winnerTeam;
final bool kot;
final bool hakemKot;
final int points;
final List<int> scores;
HandResult.fromJson(Map<String, dynamic> j)
: winnerTeam = (j['winner_team'] ?? 0) as int,
kot = (j['kot'] ?? false) as bool,
hakemKot = (j['hakem_kot'] ?? false) as bool,
points = (j['points'] ?? 0) as int,
scores =
((j['scores'] as List?) ?? []).map((e) => (e as num).toInt()).toList();
}
/// نتیجه‌ی پایان بازی (پیام type=game_over).
class GameOver {
final int winnerTeam;
final List<int> scores;
GameOver.fromJson(Map<String, dynamic> j)
: winnerTeam = (j['winner_team'] ?? 0) as int,
scores =
((j['scores'] as List?) ?? []).map((e) => (e as num).toInt()).toList();
}
extension FirstOrNullExt<E> on Iterable<E> {
E? get firstOrNull {
final it = iterator;
return it.moveNext() ? it.current : null;
}
}
@@ -0,0 +1,42 @@
/// نوع میز (از catalog.table_tiers در GET /api/shop).
class TableTier {
final String id;
final String title;
final int hands;
final int entry;
final int prize;
final int xp;
final int trophy;
const TableTier({
required this.id,
required this.title,
required this.hands,
required this.entry,
required this.prize,
required this.xp,
required this.trophy,
});
factory TableTier.fromJson(Map<String, dynamic> j) => TableTier(
id: j['id'] as String,
title: j['title'] as String,
hands: (j['hands'] ?? 0) as int,
entry: (j['entry'] ?? 0) as int,
prize: (j['prize'] ?? 0) as int,
xp: (j['xp'] ?? 0) as int,
trophy: (j['trophy'] ?? 0) as int,
);
}
/// اطلاعات سهمیه‌ی میزهای خصوصی (GET /api/tables/info).
class TablesInfo {
final int remaining;
final bool unlimited;
const TablesInfo(this.remaining, this.unlimited);
factory TablesInfo.fromJson(Map<String, dynamic> j) => TablesInfo(
(j['remaining'] ?? 0) as int,
(j['unlimited'] ?? false) as bool,
);
}
@@ -0,0 +1,17 @@
import '../../../../core/network/ws_client.dart';
import '../../../../core/resources/data_state.dart';
import '../entities/table_entities.dart';
/// قرارداد دادهٔ بازی: بخش realtime (سوکت) + بخش HTTP (میزها/سهمیه).
abstract class GameRepository {
// --- realtime ---
Stream<Map<String, dynamic>> get messages;
Stream<WsStatus> get status;
Future<void> connect();
void send(Map<String, dynamic> msg);
Future<void> disconnect();
// --- HTTP ---
Future<DataState<List<TableTier>>> getTiers();
Future<DataState<TablesInfo>> getTablesInfo();
}
@@ -0,0 +1,14 @@
import '../../../../core/resources/data_state.dart';
import '../../../../core/usecase/use_case.dart';
import '../entities/table_entities.dart';
import '../repository/game_repository.dart';
class GetTablesInfoUseCase
implements UseCase<DataState<TablesInfo>, NoParams> {
final GameRepository repository;
GetTablesInfoUseCase(this.repository);
@override
Future<DataState<TablesInfo>> call(NoParams params) =>
repository.getTablesInfo();
}
@@ -0,0 +1,14 @@
import '../../../../core/resources/data_state.dart';
import '../../../../core/usecase/use_case.dart';
import '../entities/table_entities.dart';
import '../repository/game_repository.dart';
class GetTiersUseCase
implements UseCase<DataState<List<TableTier>>, NoParams> {
final GameRepository repository;
GetTiersUseCase(this.repository);
@override
Future<DataState<List<TableTier>>> call(NoParams params) =>
repository.getTiers();
}