From eb6272334d729f76fbf1bf664526a775e8badcaa Mon Sep 17 00:00:00 2001 From: CodeDoctorDE Date: Tue, 9 May 2023 09:47:11 +0200 Subject: [PATCH] Add seat and deck creation --- app/lib/l10n/app_en.arb | 9 +- app/lib/logic/connection/client.dart | 24 +++ app/lib/logic/connection/client.freezed.dart | 15 +- app/lib/logic/connection/client.g.dart | 29 ++- app/lib/logic/connection/logic.g.dart | 3 +- app/lib/logic/connection/server.dart | 25 ++- app/lib/logic/connection/server.freezed.dart | 193 ++++++++++-------- app/lib/logic/connection/server.g.dart | 61 +++--- app/lib/logic/state.freezed.dart | 12 +- app/lib/logic/state.g.dart | 49 ++--- app/lib/pages/game/deck.dart | 195 ++++++++++++++++--- app/lib/pages/game/seat.dart | 118 +++++++++++ app/lib/pages/game/view.dart | 61 ++++-- 13 files changed, 570 insertions(+), 224 deletions(-) create mode 100644 app/lib/pages/game/seat.dart diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index ebed38fa..59509395 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -18,5 +18,12 @@ "seat": "Seat", "shuffle": "Shuffle", "decks": "Decks", - "cards": "Cards" + "cards": "Cards", + "classic": "Classic", + "available": "Available", + "seats": "Seats", + "addDeck": "Add deck", + "addSeat": "Add seat", + "visibility": "Visibility", + "ownVisibility": "Own visibility" } diff --git a/app/lib/logic/connection/client.dart b/app/lib/logic/connection/client.dart index 2e45ffe0..a7a05bdf 100644 --- a/app/lib/logic/connection/client.dart +++ b/app/lib/logic/connection/client.dart @@ -86,4 +86,28 @@ class ClientGameConnection with GameConnection, ConnectedGameConnection { Future close() async { await channel.sink.close(); } + + List getMySeats() => state.seats + .where((element) => element.players.any((e) => e == playerId)) + .toList(); + + void addSeat(String name) { + send(ServerConnectionMessage.addSeat(name)); + } + + void leaveSeat(int key) { + send(ServerConnectionMessage.leaveSeat(key)); + } + + void joinSeat(int key) { + send(ServerConnectionMessage.joinSeat(key)); + } + + void removeSeat(int key) { + send(ServerConnectionMessage.removeSeat(key)); + } + + void addDeck(GameDeck deck, int? seatIndex) { + send(ServerConnectionMessage.addDeck(deck, seatIndex)); + } } diff --git a/app/lib/logic/connection/client.freezed.dart b/app/lib/logic/connection/client.freezed.dart index 075b1761..3ee0d647 100644 --- a/app/lib/logic/connection/client.freezed.dart +++ b/app/lib/logic/connection/client.freezed.dart @@ -16,7 +16,7 @@ final _privateConstructorUsedError = UnsupportedError( ClientConnectionMessage _$ClientConnectionMessageFromJson( Map json) { - switch (json['runtimeType']) { + switch (json['type']) { case 'playersUpdated': return FetchedPlayersClientConnectionMessage.fromJson(json); case 'chatMessage': @@ -25,11 +25,8 @@ ClientConnectionMessage _$ClientConnectionMessageFromJson( return GameStateChangedClientConnectionMessage.fromJson(json); default: - throw CheckedFromJsonException( - json, - 'runtimeType', - 'ClientConnectionMessage', - 'Invalid union type "${json['runtimeType']}"!'); + throw CheckedFromJsonException(json, 'type', 'ClientConnectionMessage', + 'Invalid union type "${json['type']}"!'); } } @@ -173,7 +170,7 @@ class _$FetchedPlayersClientConnectionMessage @override final int playerId; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -362,7 +359,7 @@ class _$ChatMessageClientConnectionMessage @override final String from; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -552,7 +549,7 @@ class _$GameStateChangedClientConnectionMessage @override final GameState state; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override diff --git a/app/lib/logic/connection/client.g.dart b/app/lib/logic/connection/client.g.dart index a17cbbfc..bc1d791d 100644 --- a/app/lib/logic/connection/client.g.dart +++ b/app/lib/logic/connection/client.g.dart @@ -7,30 +7,30 @@ part of 'client.dart'; // ************************************************************************** _$FetchedPlayersClientConnectionMessage - _$$FetchedPlayersClientConnectionMessageFromJson( - Map json) => + _$$FetchedPlayersClientConnectionMessageFromJson(Map json) => _$FetchedPlayersClientConnectionMessage( (json['players'] as List) - .map((e) => GamePlayer.fromJson(e as Map)) + .map((e) => + GamePlayer.fromJson(Map.from(e as Map))) .toList(), json['playerId'] as int, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$FetchedPlayersClientConnectionMessageToJson( _$FetchedPlayersClientConnectionMessage instance) => { - 'players': instance.players, + 'players': instance.players.map((e) => e.toJson()).toList(), 'playerId': instance.playerId, - 'runtimeType': instance.$type, + 'type': instance.$type, }; _$ChatMessageClientConnectionMessage - _$$ChatMessageClientConnectionMessageFromJson(Map json) => + _$$ChatMessageClientConnectionMessageFromJson(Map json) => _$ChatMessageClientConnectionMessage( json['message'] as String, json['from'] as String, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$ChatMessageClientConnectionMessageToJson( @@ -38,20 +38,19 @@ Map _$$ChatMessageClientConnectionMessageToJson( { 'message': instance.message, 'from': instance.from, - 'runtimeType': instance.$type, + 'type': instance.$type, }; _$GameStateChangedClientConnectionMessage - _$$GameStateChangedClientConnectionMessageFromJson( - Map json) => + _$$GameStateChangedClientConnectionMessageFromJson(Map json) => _$GameStateChangedClientConnectionMessage( - GameState.fromJson(json['state'] as Map), - $type: json['runtimeType'] as String?, + GameState.fromJson(Map.from(json['state'] as Map)), + $type: json['type'] as String?, ); Map _$$GameStateChangedClientConnectionMessageToJson( _$GameStateChangedClientConnectionMessage instance) => { - 'state': instance.state, - 'runtimeType': instance.$type, + 'state': instance.state.toJson(), + 'type': instance.$type, }; diff --git a/app/lib/logic/connection/logic.g.dart b/app/lib/logic/connection/logic.g.dart index 75390fcd..7074e786 100644 --- a/app/lib/logic/connection/logic.g.dart +++ b/app/lib/logic/connection/logic.g.dart @@ -6,8 +6,7 @@ part of 'logic.dart'; // JsonSerializableGenerator // ************************************************************************** -_$_GamePlayer _$$_GamePlayerFromJson(Map json) => - _$_GamePlayer( +_$_GamePlayer _$$_GamePlayerFromJson(Map json) => _$_GamePlayer( name: json['name'] as String, id: json['id'] as String, ); diff --git a/app/lib/logic/connection/server.dart b/app/lib/logic/connection/server.dart index d6df5438..35600606 100644 --- a/app/lib/logic/connection/server.dart +++ b/app/lib/logic/connection/server.dart @@ -20,10 +20,10 @@ class ServerConnectionMessage with _$ServerConnectionMessage { const factory ServerConnectionMessage.chatMessage(String message) = ChatMessageServerConnectionMessage; - const factory ServerConnectionMessage.addDeck(GameDeck deck) = + const factory ServerConnectionMessage.addDeck(GameDeck deck, int? seatIndex) = AddDeckServerConnectionMessage; - const factory ServerConnectionMessage.removeDeck(int index) = + const factory ServerConnectionMessage.removeDeck(int index, int? seatIndex) = RemoveDeckServerConnectionMessage; const factory ServerConnectionMessage.addSeat(String name, @@ -151,10 +151,27 @@ class ServerGameConnection with GameConnection { client.info.remoteAddress.address, ), ), - addDeck: (deck) { + addDeck: (deck, seatIndex) { + if (seatIndex != null) { + _changeState(state.copyWith( + seats: List.from(state.seats) + ..[seatIndex] = state.seats[seatIndex].copyWith( + decks: [...state.seats[seatIndex].decks, deck], + ))); + return; + } _changeState(state.copyWith(decks: [...state.decks, deck])); }, - removeDeck: (index) { + removeDeck: (index, seatIndex) { + if (seatIndex != null) { + _changeState(state.copyWith( + seats: List.from(state.seats) + ..[seatIndex] = state.seats[seatIndex].copyWith( + decks: List.from(state.seats[seatIndex].decks) + ..removeAt(index), + ))); + return; + } _changeState(state.copyWith( decks: List.from(state.decks)..removeAt(index))); }, diff --git a/app/lib/logic/connection/server.freezed.dart b/app/lib/logic/connection/server.freezed.dart index 8c78d2ce..16030bcd 100644 --- a/app/lib/logic/connection/server.freezed.dart +++ b/app/lib/logic/connection/server.freezed.dart @@ -16,7 +16,7 @@ final _privateConstructorUsedError = UnsupportedError( ServerConnectionMessage _$ServerConnectionMessageFromJson( Map json) { - switch (json['runtimeType']) { + switch (json['type']) { case 'fetchPlayers': return FetchPlayersServerConnectionMessage.fromJson(json); case 'chatMessage': @@ -35,11 +35,8 @@ ServerConnectionMessage _$ServerConnectionMessageFromJson( return LeaveSeatServerConnectionMessage.fromJson(json); default: - throw CheckedFromJsonException( - json, - 'runtimeType', - 'ServerConnectionMessage', - 'Invalid union type "${json['runtimeType']}"!'); + throw CheckedFromJsonException(json, 'type', 'ServerConnectionMessage', + 'Invalid union type "${json['type']}"!'); } } @@ -49,8 +46,8 @@ mixin _$ServerConnectionMessage { TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, @@ -61,8 +58,8 @@ mixin _$ServerConnectionMessage { TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, @@ -73,8 +70,8 @@ mixin _$ServerConnectionMessage { TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -175,7 +172,7 @@ class _$FetchPlayersServerConnectionMessage Map json) => _$$FetchPlayersServerConnectionMessageFromJson(json); - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -199,8 +196,8 @@ class _$FetchPlayersServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, @@ -214,8 +211,8 @@ class _$FetchPlayersServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, @@ -229,8 +226,8 @@ class _$FetchPlayersServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -363,7 +360,7 @@ class _$ChatMessageServerConnectionMessage @override final String message; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -396,8 +393,8 @@ class _$ChatMessageServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, @@ -411,8 +408,8 @@ class _$ChatMessageServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, @@ -426,8 +423,8 @@ class _$ChatMessageServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -524,7 +521,7 @@ abstract class _$$AddDeckServerConnectionMessageCopyWith<$Res> { $Res Function(_$AddDeckServerConnectionMessage) then) = __$$AddDeckServerConnectionMessageCopyWithImpl<$Res>; @useResult - $Res call({GameDeck deck}); + $Res call({GameDeck deck, int? seatIndex}); $GameDeckCopyWith<$Res> get deck; } @@ -543,12 +540,17 @@ class __$$AddDeckServerConnectionMessageCopyWithImpl<$Res> @override $Res call({ Object? deck = null, + Object? seatIndex = freezed, }) { return _then(_$AddDeckServerConnectionMessage( null == deck ? _value.deck : deck // ignore: cast_nullable_to_non_nullable as GameDeck, + freezed == seatIndex + ? _value.seatIndex + : seatIndex // ignore: cast_nullable_to_non_nullable + as int?, )); } @@ -565,7 +567,8 @@ class __$$AddDeckServerConnectionMessageCopyWithImpl<$Res> @JsonSerializable() class _$AddDeckServerConnectionMessage implements AddDeckServerConnectionMessage { - const _$AddDeckServerConnectionMessage(this.deck, {final String? $type}) + const _$AddDeckServerConnectionMessage(this.deck, this.seatIndex, + {final String? $type}) : $type = $type ?? 'addDeck'; factory _$AddDeckServerConnectionMessage.fromJson( @@ -574,13 +577,15 @@ class _$AddDeckServerConnectionMessage @override final GameDeck deck; + @override + final int? seatIndex; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override String toString() { - return 'ServerConnectionMessage.addDeck(deck: $deck)'; + return 'ServerConnectionMessage.addDeck(deck: $deck, seatIndex: $seatIndex)'; } @override @@ -588,12 +593,14 @@ class _$AddDeckServerConnectionMessage return identical(this, other) || (other.runtimeType == runtimeType && other is _$AddDeckServerConnectionMessage && - (identical(other.deck, deck) || other.deck == deck)); + (identical(other.deck, deck) || other.deck == deck) && + (identical(other.seatIndex, seatIndex) || + other.seatIndex == seatIndex)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, deck); + int get hashCode => Object.hash(runtimeType, deck, seatIndex); @JsonKey(ignore: true) @override @@ -607,14 +614,14 @@ class _$AddDeckServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, required TResult Function(int index) leaveSeat, }) { - return addDeck(deck); + return addDeck(deck, seatIndex); } @override @@ -622,14 +629,14 @@ class _$AddDeckServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, TResult? Function(int index)? leaveSeat, }) { - return addDeck?.call(deck); + return addDeck?.call(deck, seatIndex); } @override @@ -637,8 +644,8 @@ class _$AddDeckServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -646,7 +653,7 @@ class _$AddDeckServerConnectionMessage required TResult orElse(), }) { if (addDeck != null) { - return addDeck(deck); + return addDeck(deck, seatIndex); } return orElse(); } @@ -714,13 +721,15 @@ class _$AddDeckServerConnectionMessage abstract class AddDeckServerConnectionMessage implements ServerConnectionMessage { - const factory AddDeckServerConnectionMessage(final GameDeck deck) = + const factory AddDeckServerConnectionMessage( + final GameDeck deck, final int? seatIndex) = _$AddDeckServerConnectionMessage; factory AddDeckServerConnectionMessage.fromJson(Map json) = _$AddDeckServerConnectionMessage.fromJson; GameDeck get deck; + int? get seatIndex; @JsonKey(ignore: true) _$$AddDeckServerConnectionMessageCopyWith<_$AddDeckServerConnectionMessage> get copyWith => throw _privateConstructorUsedError; @@ -733,7 +742,7 @@ abstract class _$$RemoveDeckServerConnectionMessageCopyWith<$Res> { $Res Function(_$RemoveDeckServerConnectionMessage) then) = __$$RemoveDeckServerConnectionMessageCopyWithImpl<$Res>; @useResult - $Res call({int index}); + $Res call({int index, int? seatIndex}); } /// @nodoc @@ -750,12 +759,17 @@ class __$$RemoveDeckServerConnectionMessageCopyWithImpl<$Res> @override $Res call({ Object? index = null, + Object? seatIndex = freezed, }) { return _then(_$RemoveDeckServerConnectionMessage( null == index ? _value.index : index // ignore: cast_nullable_to_non_nullable as int, + freezed == seatIndex + ? _value.seatIndex + : seatIndex // ignore: cast_nullable_to_non_nullable + as int?, )); } } @@ -764,7 +778,8 @@ class __$$RemoveDeckServerConnectionMessageCopyWithImpl<$Res> @JsonSerializable() class _$RemoveDeckServerConnectionMessage implements RemoveDeckServerConnectionMessage { - const _$RemoveDeckServerConnectionMessage(this.index, {final String? $type}) + const _$RemoveDeckServerConnectionMessage(this.index, this.seatIndex, + {final String? $type}) : $type = $type ?? 'removeDeck'; factory _$RemoveDeckServerConnectionMessage.fromJson( @@ -773,13 +788,15 @@ class _$RemoveDeckServerConnectionMessage @override final int index; + @override + final int? seatIndex; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override String toString() { - return 'ServerConnectionMessage.removeDeck(index: $index)'; + return 'ServerConnectionMessage.removeDeck(index: $index, seatIndex: $seatIndex)'; } @override @@ -787,12 +804,14 @@ class _$RemoveDeckServerConnectionMessage return identical(this, other) || (other.runtimeType == runtimeType && other is _$RemoveDeckServerConnectionMessage && - (identical(other.index, index) || other.index == index)); + (identical(other.index, index) || other.index == index) && + (identical(other.seatIndex, seatIndex) || + other.seatIndex == seatIndex)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, index); + int get hashCode => Object.hash(runtimeType, index, seatIndex); @JsonKey(ignore: true) @override @@ -807,14 +826,14 @@ class _$RemoveDeckServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, required TResult Function(int index) leaveSeat, }) { - return removeDeck(index); + return removeDeck(index, seatIndex); } @override @@ -822,14 +841,14 @@ class _$RemoveDeckServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, TResult? Function(int index)? leaveSeat, }) { - return removeDeck?.call(index); + return removeDeck?.call(index, seatIndex); } @override @@ -837,8 +856,8 @@ class _$RemoveDeckServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -846,7 +865,7 @@ class _$RemoveDeckServerConnectionMessage required TResult orElse(), }) { if (removeDeck != null) { - return removeDeck(index); + return removeDeck(index, seatIndex); } return orElse(); } @@ -914,13 +933,15 @@ class _$RemoveDeckServerConnectionMessage abstract class RemoveDeckServerConnectionMessage implements ServerConnectionMessage { - const factory RemoveDeckServerConnectionMessage(final int index) = + const factory RemoveDeckServerConnectionMessage( + final int index, final int? seatIndex) = _$RemoveDeckServerConnectionMessage; factory RemoveDeckServerConnectionMessage.fromJson( Map json) = _$RemoveDeckServerConnectionMessage.fromJson; int get index; + int? get seatIndex; @JsonKey(ignore: true) _$$RemoveDeckServerConnectionMessageCopyWith< _$RemoveDeckServerConnectionMessage> @@ -990,7 +1011,7 @@ class _$AddSeatServerConnectionMessage return EqualUnmodifiableListView(_decks); } - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -1024,8 +1045,8 @@ class _$AddSeatServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, @@ -1039,8 +1060,8 @@ class _$AddSeatServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, @@ -1054,8 +1075,8 @@ class _$AddSeatServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -1192,7 +1213,7 @@ class _$RemoveSeatServerConnectionMessage @override final int index; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -1225,8 +1246,8 @@ class _$RemoveSeatServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, @@ -1240,8 +1261,8 @@ class _$RemoveSeatServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, @@ -1255,8 +1276,8 @@ class _$RemoveSeatServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -1393,7 +1414,7 @@ class _$JoinSeatServerConnectionMessage @override final int index; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -1425,8 +1446,8 @@ class _$JoinSeatServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, @@ -1440,8 +1461,8 @@ class _$JoinSeatServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, @@ -1455,8 +1476,8 @@ class _$JoinSeatServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, @@ -1592,7 +1613,7 @@ class _$LeaveSeatServerConnectionMessage @override final int index; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -1625,8 +1646,8 @@ class _$LeaveSeatServerConnectionMessage TResult when({ required TResult Function() fetchPlayers, required TResult Function(String message) chatMessage, - required TResult Function(GameDeck deck) addDeck, - required TResult Function(int index) removeDeck, + required TResult Function(GameDeck deck, int? seatIndex) addDeck, + required TResult Function(int index, int? seatIndex) removeDeck, required TResult Function(String name, List decks) addSeat, required TResult Function(int index) removeSeat, required TResult Function(int index) joinSeat, @@ -1640,8 +1661,8 @@ class _$LeaveSeatServerConnectionMessage TResult? whenOrNull({ TResult? Function()? fetchPlayers, TResult? Function(String message)? chatMessage, - TResult? Function(GameDeck deck)? addDeck, - TResult? Function(int index)? removeDeck, + TResult? Function(GameDeck deck, int? seatIndex)? addDeck, + TResult? Function(int index, int? seatIndex)? removeDeck, TResult? Function(String name, List decks)? addSeat, TResult? Function(int index)? removeSeat, TResult? Function(int index)? joinSeat, @@ -1655,8 +1676,8 @@ class _$LeaveSeatServerConnectionMessage TResult maybeWhen({ TResult Function()? fetchPlayers, TResult Function(String message)? chatMessage, - TResult Function(GameDeck deck)? addDeck, - TResult Function(int index)? removeDeck, + TResult Function(GameDeck deck, int? seatIndex)? addDeck, + TResult Function(int index, int? seatIndex)? removeDeck, TResult Function(String name, List decks)? addSeat, TResult Function(int index)? removeSeat, TResult Function(int index)? joinSeat, diff --git a/app/lib/logic/connection/server.g.dart b/app/lib/logic/connection/server.g.dart index 830f1a8c..0b4cb5b1 100644 --- a/app/lib/logic/connection/server.g.dart +++ b/app/lib/logic/connection/server.g.dart @@ -7,116 +7,121 @@ part of 'server.dart'; // ************************************************************************** _$FetchPlayersServerConnectionMessage - _$$FetchPlayersServerConnectionMessageFromJson(Map json) => + _$$FetchPlayersServerConnectionMessageFromJson(Map json) => _$FetchPlayersServerConnectionMessage( - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$FetchPlayersServerConnectionMessageToJson( _$FetchPlayersServerConnectionMessage instance) => { - 'runtimeType': instance.$type, + 'type': instance.$type, }; _$ChatMessageServerConnectionMessage - _$$ChatMessageServerConnectionMessageFromJson(Map json) => + _$$ChatMessageServerConnectionMessageFromJson(Map json) => _$ChatMessageServerConnectionMessage( json['message'] as String, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$ChatMessageServerConnectionMessageToJson( _$ChatMessageServerConnectionMessage instance) => { 'message': instance.message, - 'runtimeType': instance.$type, + 'type': instance.$type, }; _$AddDeckServerConnectionMessage _$$AddDeckServerConnectionMessageFromJson( - Map json) => + Map json) => _$AddDeckServerConnectionMessage( - GameDeck.fromJson(json['deck'] as Map), - $type: json['runtimeType'] as String?, + GameDeck.fromJson(Map.from(json['deck'] as Map)), + json['seatIndex'] as int?, + $type: json['type'] as String?, ); Map _$$AddDeckServerConnectionMessageToJson( _$AddDeckServerConnectionMessage instance) => { - 'deck': instance.deck, - 'runtimeType': instance.$type, + 'deck': instance.deck.toJson(), + 'seatIndex': instance.seatIndex, + 'type': instance.$type, }; _$RemoveDeckServerConnectionMessage - _$$RemoveDeckServerConnectionMessageFromJson(Map json) => + _$$RemoveDeckServerConnectionMessageFromJson(Map json) => _$RemoveDeckServerConnectionMessage( json['index'] as int, - $type: json['runtimeType'] as String?, + json['seatIndex'] as int?, + $type: json['type'] as String?, ); Map _$$RemoveDeckServerConnectionMessageToJson( _$RemoveDeckServerConnectionMessage instance) => { 'index': instance.index, - 'runtimeType': instance.$type, + 'seatIndex': instance.seatIndex, + 'type': instance.$type, }; _$AddSeatServerConnectionMessage _$$AddSeatServerConnectionMessageFromJson( - Map json) => + Map json) => _$AddSeatServerConnectionMessage( json['name'] as String, (json['decks'] as List?) - ?.map((e) => GameDeck.fromJson(e as Map)) + ?.map( + (e) => GameDeck.fromJson(Map.from(e as Map))) .toList() ?? const [], - json['runtimeType'] as String?, + json['type'] as String?, ); Map _$$AddSeatServerConnectionMessageToJson( _$AddSeatServerConnectionMessage instance) => { 'name': instance.name, - 'decks': instance.decks, - 'runtimeType': instance.$type, + 'decks': instance.decks.map((e) => e.toJson()).toList(), + 'type': instance.$type, }; _$RemoveSeatServerConnectionMessage - _$$RemoveSeatServerConnectionMessageFromJson(Map json) => + _$$RemoveSeatServerConnectionMessageFromJson(Map json) => _$RemoveSeatServerConnectionMessage( json['index'] as int, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$RemoveSeatServerConnectionMessageToJson( _$RemoveSeatServerConnectionMessage instance) => { 'index': instance.index, - 'runtimeType': instance.$type, + 'type': instance.$type, }; _$JoinSeatServerConnectionMessage _$$JoinSeatServerConnectionMessageFromJson( - Map json) => + Map json) => _$JoinSeatServerConnectionMessage( json['index'] as int, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$JoinSeatServerConnectionMessageToJson( _$JoinSeatServerConnectionMessage instance) => { 'index': instance.index, - 'runtimeType': instance.$type, + 'type': instance.$type, }; _$LeaveSeatServerConnectionMessage _$$LeaveSeatServerConnectionMessageFromJson( - Map json) => + Map json) => _$LeaveSeatServerConnectionMessage( json['index'] as int, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$LeaveSeatServerConnectionMessageToJson( _$LeaveSeatServerConnectionMessage instance) => { 'index': instance.index, - 'runtimeType': instance.$type, + 'type': instance.$type, }; diff --git a/app/lib/logic/state.freezed.dart b/app/lib/logic/state.freezed.dart index f59ae14a..6af31382 100644 --- a/app/lib/logic/state.freezed.dart +++ b/app/lib/logic/state.freezed.dart @@ -652,7 +652,7 @@ abstract class _GameSeat extends GameSeat { } DeckRefill _$DeckRefillFromJson(Map json) { - switch (json['runtimeType']) { + switch (json['type']) { case 'none': return _DeckRefillNone.fromJson(json); case 'shuffle': @@ -661,8 +661,8 @@ DeckRefill _$DeckRefillFromJson(Map json) { return _DeckRefillFirst.fromJson(json); default: - throw CheckedFromJsonException(json, 'runtimeType', 'DeckRefill', - 'Invalid union type "${json['runtimeType']}"!'); + throw CheckedFromJsonException( + json, 'type', 'DeckRefill', 'Invalid union type "${json['type']}"!'); } } @@ -759,7 +759,7 @@ class _$_DeckRefillNone extends _DeckRefillNone { factory _$_DeckRefillNone.fromJson(Map json) => _$$_DeckRefillNoneFromJson(json); - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -905,7 +905,7 @@ class _$_DeckRefillShuffle extends _DeckRefillShuffle { @override final int? count; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override @@ -1065,7 +1065,7 @@ class _$_DeckRefillFirst extends _DeckRefillFirst { @override final int? count; - @JsonKey(name: 'runtimeType') + @JsonKey(name: 'type') final String $type; @override diff --git a/app/lib/logic/state.g.dart b/app/lib/logic/state.g.dart index 05fe14ba..b025fe36 100644 --- a/app/lib/logic/state.g.dart +++ b/app/lib/logic/state.g.dart @@ -6,8 +6,7 @@ part of 'state.dart'; // JsonSerializableGenerator // ************************************************************************** -_$ClassicGameCard _$$ClassicGameCardFromJson(Map json) => - _$ClassicGameCard( +_$ClassicGameCard _$$ClassicGameCardFromJson(Map json) => _$ClassicGameCard( color: $enumDecodeNullable(_$ClassicGameCardColorEnumMap, json['color']) ?? ClassicGameCardColor.heart, @@ -27,27 +26,30 @@ const _$ClassicGameCardColorEnumMap = { ClassicGameCardColor.club: 'club', }; -_$_GameState _$$_GameStateFromJson(Map json) => _$_GameState( +_$_GameState _$$_GameStateFromJson(Map json) => _$_GameState( decks: (json['decks'] as List?) - ?.map((e) => GameDeck.fromJson(e as Map)) + ?.map( + (e) => GameDeck.fromJson(Map.from(e as Map))) .toList() ?? const [], seats: (json['seats'] as List?) - ?.map((e) => GameSeat.fromJson(e as Map)) + ?.map( + (e) => GameSeat.fromJson(Map.from(e as Map))) .toList() ?? const [], ); Map _$$_GameStateToJson(_$_GameState instance) => { - 'decks': instance.decks, - 'seats': instance.seats, + 'decks': instance.decks.map((e) => e.toJson()).toList(), + 'seats': instance.seats.map((e) => e.toJson()).toList(), }; -_$_GameSeat _$$_GameSeatFromJson(Map json) => _$_GameSeat( +_$_GameSeat _$$_GameSeatFromJson(Map json) => _$_GameSeat( name: json['name'] as String? ?? '', decks: (json['decks'] as List?) - ?.map((e) => GameDeck.fromJson(e as Map)) + ?.map( + (e) => GameDeck.fromJson(Map.from(e as Map))) .toList() ?? const [], players: @@ -60,7 +62,7 @@ _$_GameSeat _$$_GameSeatFromJson(Map json) => _$_GameSeat( Map _$$_GameSeatToJson(_$_GameSeat instance) => { 'name': instance.name, - 'decks': instance.decks, + 'decks': instance.decks.map((e) => e.toJson()).toList(), 'players': instance.players, 'ownDeckVisibility': _$DeckVisibilityEnumMap[instance.ownDeckVisibility], }; @@ -71,42 +73,40 @@ const _$DeckVisibilityEnumMap = { DeckVisibility.visible: 'visible', }; -_$_DeckRefillNone _$$_DeckRefillNoneFromJson(Map json) => - _$_DeckRefillNone( - $type: json['runtimeType'] as String?, +_$_DeckRefillNone _$$_DeckRefillNoneFromJson(Map json) => _$_DeckRefillNone( + $type: json['type'] as String?, ); Map _$$_DeckRefillNoneToJson(_$_DeckRefillNone instance) => { - 'runtimeType': instance.$type, + 'type': instance.$type, }; -_$_DeckRefillShuffle _$$_DeckRefillShuffleFromJson(Map json) => +_$_DeckRefillShuffle _$$_DeckRefillShuffleFromJson(Map json) => _$_DeckRefillShuffle( count: json['count'] as int?, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$_DeckRefillShuffleToJson( _$_DeckRefillShuffle instance) => { 'count': instance.count, - 'runtimeType': instance.$type, + 'type': instance.$type, }; -_$_DeckRefillFirst _$$_DeckRefillFirstFromJson(Map json) => - _$_DeckRefillFirst( +_$_DeckRefillFirst _$$_DeckRefillFirstFromJson(Map json) => _$_DeckRefillFirst( count: json['count'] as int?, - $type: json['runtimeType'] as String?, + $type: json['type'] as String?, ); Map _$$_DeckRefillFirstToJson(_$_DeckRefillFirst instance) => { 'count': instance.count, - 'runtimeType': instance.$type, + 'type': instance.$type, }; -_$_GameDeck _$$_GameDeckFromJson(Map json) => _$_GameDeck( +_$_GameDeck _$$_GameDeckFromJson(Map json) => _$_GameDeck( name: json['name'] as String? ?? '', visibility: $enumDecodeNullable(_$DeckVisibilityEnumMap, json['visibility']) ?? @@ -114,7 +114,8 @@ _$_GameDeck _$$_GameDeckFromJson(Map json) => _$_GameDeck( ownVisibility: $enumDecodeNullable(_$DeckVisibilityEnumMap, json['ownVisibility']), cards: (json['cards'] as List?) - ?.map((e) => GameCard.fromJson(e as Map)) + ?.map( + (e) => GameCard.fromJson(Map.from(e as Map))) .toList() ?? const [], ); @@ -124,5 +125,5 @@ Map _$$_GameDeckToJson(_$_GameDeck instance) => 'name': instance.name, 'visibility': _$DeckVisibilityEnumMap[instance.visibility]!, 'ownVisibility': _$DeckVisibilityEnumMap[instance.ownVisibility], - 'cards': instance.cards, + 'cards': instance.cards.map((e) => e.toJson()).toList(), }; diff --git a/app/lib/pages/game/deck.dart b/app/lib/pages/game/deck.dart index fb8e8f85..7efe3ad5 100644 --- a/app/lib/pages/game/deck.dart +++ b/app/lib/pages/game/deck.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:phosphor_flutter/phosphor_flutter.dart'; @@ -5,15 +6,20 @@ import 'package:qeck/logic/connection/client.dart'; import 'package:qeck/logic/state.dart'; import 'package:qeck/pages/game/card.dart'; -class CardLocation { +class DeckLocation { final GameDeck deck; + final int? index; + final int? seatIndex; + + DeckLocation(this.deck, this.index, this.seatIndex); +} + +class CardLocation { final GameCard card; final int index; - final int? deckIndex; - final int? seatIndex; + final DeckLocation location; - CardLocation( - this.deck, this.card, this.index, this.deckIndex, this.seatIndex); + CardLocation(this.card, this.index, this.location); } class GameDeckView extends StatelessWidget { @@ -32,37 +38,162 @@ class GameDeckView extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - children: [ - SizedBox( - height: 100, - child: ListView( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - children: deck.cards - .asMap() - .entries - .map((e) => CardView( - card: e.value, - )) - .toList(), + final firstCard = deck.cards.firstOrNull; + return SizedBox( + width: 120, + child: Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (firstCard != null) + Expanded( + child: Draggable( + data: DeckLocation(deck, index, seatIndex), + feedback: Material( + child: Text(deck.name), + ), + child: CardView( + card: firstCard, + ), + ), + ), + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text(deck.name), + MenuAnchor( + builder: (context, controller, child) => IconButton( + icon: const PhosphorIcon(PhosphorIconsLight.list), + onPressed: () => controller.isOpen + ? controller.close() + : controller.open(), + ), + menuChildren: [ + MenuItemButton( + child: Text(AppLocalizations.of(context).shuffle), + ) + ], + ), + ]), + ], ), ), - Row(children: [ - Expanded(child: Text(deck.name)), - MenuAnchor( - builder: (context, controller, child) => IconButton( - icon: const PhosphorIcon(PhosphorIconsLight.list), - onPressed: () => - controller.isOpen ? controller.close() : controller.open(), + ), + ); + } +} + +class AddDeckView extends StatelessWidget { + final ClientGameConnection connection; + const AddDeckView({super.key, required this.connection}); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 120, + child: Card( + clipBehavior: Clip.antiAlias, + child: InkWell( + onTap: () => showDialog( + context: context, + builder: (context) => AddDeckDialog( + connection: connection, ), - menuChildren: [ - MenuItemButton( - child: Text(AppLocalizations.of(context).shuffle), - ) - ], ), - ]), + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Align( + child: PhosphorIcon(PhosphorIconsLight.plus, size: 32), + ), + ), + ), + ), + ); + } +} + +class AddDeckDialog extends StatelessWidget { + final ClientGameConnection connection; + final int? seatIndex; + + const AddDeckDialog({super.key, required this.connection, this.seatIndex}); + + @override + Widget build(BuildContext context) { + GameDeck deck = const GameDeck(); + return AlertDialog( + title: Text(AppLocalizations.of(context).addDeck), + scrollable: true, + content: SizedBox( + width: 500, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + decoration: InputDecoration( + labelText: AppLocalizations.of(context).name, + ), + onChanged: (value) => deck = deck.copyWith(name: value), + ), + DropdownButtonFormField( + decoration: InputDecoration( + labelText: AppLocalizations.of(context).visibility, + ), + value: deck.visibility, + items: DeckVisibility.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.name), + )) + .toList(), + onChanged: (value) => + deck = deck.copyWith(visibility: value ?? deck.visibility), + ), + if (seatIndex != null) + StatefulBuilder( + builder: (context, setState) => Row( + children: [ + Expanded( + child: DropdownButtonFormField( + decoration: InputDecoration( + labelText: AppLocalizations.of(context).ownVisibility, + ), + value: deck.ownVisibility, + items: DeckVisibility.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.name), + )) + .toList(), + onChanged: (value) => setState(() => deck = + deck.copyWith( + ownVisibility: value ?? deck.ownVisibility)), + ), + ), + const SizedBox(width: 16), + IconButton( + icon: const PhosphorIcon(PhosphorIconsLight.trash), + onPressed: () => setState( + () => deck = deck.copyWith(ownVisibility: null)), + ), + ], + ), + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(AppLocalizations.of(context).cancel), + ), + ElevatedButton( + onPressed: () { + connection.addDeck(deck, seatIndex); + Navigator.of(context).pop(); + }, + child: Text(AppLocalizations.of(context).create), + ), ], ); } diff --git a/app/lib/pages/game/seat.dart b/app/lib/pages/game/seat.dart new file mode 100644 index 00000000..81e41e13 --- /dev/null +++ b/app/lib/pages/game/seat.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:phosphor_flutter/phosphor_flutter.dart'; +import 'package:qeck/logic/connection/client.dart'; +import 'package:qeck/logic/state.dart'; + +class SeatsDialog extends StatelessWidget { + final ClientGameConnection connection; + + const SeatsDialog({super.key, required this.connection}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(AppLocalizations.of(context).seats), + scrollable: true, + content: SizedBox( + width: 300, + child: StreamBuilder( + stream: connection.stateStream, + builder: (context, snapshot) { + final state = snapshot.data!; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ...state.seats.asMap().entries.map( + (e) { + final seat = e.value; + final selected = + seat.players.contains(connection.playerId); + return ListTile( + title: Text(seat.name), + selected: selected, + leading: selected + ? IconButton( + icon: + const PhosphorIcon(PhosphorIconsLight.door), + onPressed: () => connection.leaveSeat(e.key), + ) + : IconButton( + icon: const PhosphorIcon( + PhosphorIconsLight.doorOpen), + onPressed: () => connection.joinSeat(e.key), + ), + trailing: IconButton( + icon: const PhosphorIcon(PhosphorIconsLight.trash), + onPressed: () => connection.removeSeat(e.key), + ), + ); + }, + ), + if (connection.state.seats.isNotEmpty) const Divider(), + ListTile( + title: Text(AppLocalizations.of(context).create), + trailing: const Icon(Icons.add), + onTap: () { + showDialog( + context: context, + builder: (context) => + CreateSeatDialog(connection: connection)); + }, + ), + ], + ); + }), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(AppLocalizations.of(context).close), + ), + ], + ); + } +} + +class CreateSeatDialog extends StatelessWidget { + final ClientGameConnection connection; + const CreateSeatDialog({super.key, required this.connection}); + + @override + Widget build(BuildContext context) { + String name = ''; + return AlertDialog( + title: Text(AppLocalizations.of(context).addSeat), + scrollable: true, + content: SizedBox( + width: 500, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + decoration: InputDecoration( + labelText: AppLocalizations.of(context).name, + filled: true, + icon: const PhosphorIcon(PhosphorIconsLight.textT), + ), + onChanged: (value) => name = value, + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(AppLocalizations.of(context).cancel), + ), + ElevatedButton( + onPressed: () { + connection.addSeat(name); + Navigator.of(context).pop(); + }, + child: Text(AppLocalizations.of(context).create), + ), + ], + ); + } +} diff --git a/app/lib/pages/game/view.dart b/app/lib/pages/game/view.dart index 4ebdeee6..29eb6f69 100644 --- a/app/lib/pages/game/view.dart +++ b/app/lib/pages/game/view.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:phosphor_flutter/phosphor_flutter.dart'; import 'package:qeck/logic/connection/client.dart'; import 'package:qeck/logic/state.dart'; import 'deck.dart'; +import 'seat.dart'; class GameView extends StatelessWidget { final ClientGameConnection connection; @@ -24,39 +26,64 @@ class GameView extends StatelessWidget { return ListView( shrinkWrap: true, children: [ - Text(AppLocalizations.of(context).cards), + Text(AppLocalizations.of(context).available, + style: Theme.of(context).textTheme.headlineSmall), SizedBox( - height: 100, + height: 180, child: ListView( shrinkWrap: true, scrollDirection: Axis.horizontal, children: [ GameDeckView( connection: connection, - deck: GameDeck(cards: GameCard.getClassicDeck()), + deck: GameDeck( + cards: GameCard.getClassicDeck(), + name: AppLocalizations.of(context).classic), index: null, seatIndex: null, ), ], ), ), - Text(AppLocalizations.of(context).decks), + const SizedBox(height: 16), + Text(AppLocalizations.of(context).decks, + style: Theme.of(context).textTheme.headlineSmall), SizedBox( - height: 100, + height: 150, child: ListView( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - children: state.decks - .asMap() - .entries - .map((e) => GameDeckView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + children: [ + ...state.decks.asMap().entries.map((e) => GameDeckView( + connection: connection, + deck: e.value, + index: e.key, + seatIndex: null, + )), + AddDeckView(connection: connection), + ], + ), + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(AppLocalizations.of(context).seats, + style: Theme.of(context).textTheme.headlineSmall), + IconButton( + icon: const PhosphorIcon(PhosphorIconsLight.gear), + onPressed: () => showDialog( + context: context, + builder: (context) => SeatsDialog( connection: connection, - deck: e.value, - index: e.key, - seatIndex: null, - )) - .toList()), - ) + )), + ), + ], + ), + ...connection.getMySeats().expand((e) => [ + const SizedBox(height: 16), + Text(e.name), + ]) ], ); });