Skip to content

Commit 8507dcb

Browse files
committed
Improve stacked game hand navigation
1 parent fc04c35 commit 8507dcb

File tree

4 files changed

+178
-167
lines changed

4 files changed

+178
-167
lines changed

app/lib/board/hand/view.dart

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ class GameHand extends CustomPainterComponent
5757
GameHand() : super(anchor: Anchor.topLeft, painter: GameHandCustomPainter());
5858

5959
@override
60-
void update(double dt) {
60+
Future<void> update(double dt) async {
6161
if (_needsLayout) {
6262
_layoutChildren();
6363
_needsLayout = false;
6464
}
6565
if (_isDirty) {
6666
_isDirty = false;
6767
if (isMounted) {
68-
_buildHand(bloc.state);
68+
await _buildHand(bloc.state);
6969
}
7070
_needsLayout = true;
7171
}
@@ -76,8 +76,8 @@ class GameHand extends CustomPainterComponent
7676

7777
@override
7878
void onNewState(ClientWorldState state) {
79-
_currentScroll = 0;
8079
_isDirty = true;
80+
_currentScroll = 0;
8181
}
8282

8383
@override
@@ -107,21 +107,19 @@ class GameHand extends CustomPainterComponent
107107
final childrenLength = children.length;
108108
if (childrenLength == 0) return;
109109
final center = Vector2(width / 2, height);
110-
final double active = _currentScroll.clamp(0, childrenLength - 1);
110+
final double active = (_currentScroll - childrenLength + 1)
111+
.abs()
112+
.clamp(0, childrenLength - 1);
111113

112114
children.toList().whereType<HandItem>().forEachIndexed((index, element) {
113-
final double activeRelative = index - active;
115+
final double activeRelative = active - index;
114116
// Figure out how "active" this item is (0 = fully active, 1 = inactive)
115-
final progress = 1 - activeRelative.abs().clamp(0, 1);
116117
var x = center.x + 128 * activeRelative;
117118
var y = center.y;
118119
if (game.settingsCubit.state.stackedCards) {
119-
final currentWidth =
120-
itemWidth + (activeItemWidth - itemWidth) * progress;
121-
122120
final offset = activeRelative <= -1 ? -activeItemWidth / 2 : 0;
123121
y = center.y + itemYOffset * activeRelative.abs();
124-
x = center.x + offset + activeRelative * currentWidth;
122+
x = center.x + offset + activeRelative * itemWidth;
125123
element.angle = activeRelative * itemAngle;
126124
}
127125

@@ -131,47 +129,50 @@ class GameHand extends CustomPainterComponent
131129
});
132130
}
133131

134-
void _buildHand(ClientWorldState state) {
132+
Future<void> _addChildren(Iterable<Component> items) {
133+
final reversed = items.toList().reversed;
134+
return addAll(reversed);
135+
}
136+
137+
Future<void> _buildHand(ClientWorldState state) {
135138
for (final child in children) {
136139
child.removeFromParent();
137140
}
138141
painter = GameHandCustomPainter(
139142
showHand: state.showHand, color: state.colorScheme.surface);
140-
if (!state.showHand) return;
143+
if (!state.showHand) return Future.value();
141144
final selected = state.selectedCell;
142145
final cell = state.table.cells[selected];
143146
if (selected == null) {
144147
final deck = state.selectedDeck;
145148
final packItem =
146149
deck != null ? state.assetManager.getDeckItem(deck) : null;
147150
if (packItem != null) {
148-
_buildDeckHand(state, packItem, state.showDuplicates);
151+
return _buildDeckHand(state, packItem, state.showDuplicates);
149152
} else {
150-
_buildFreeHand(state);
153+
return _buildFreeHand(state);
151154
}
152155
} else {
153-
_buildCellHand(selected, cell);
156+
return _buildCellHand(selected, cell);
154157
}
155158
}
156159

157-
void _buildFreeHand(ClientWorldState state) {
160+
Future<void> _buildFreeHand(ClientWorldState state) {
158161
final decks = state.packs.expand((e) => e.value.getDeckItems(e.key));
159-
for (final deck in decks) {
160-
final item = DeckDefinitionHandItem(item: deck);
161-
if (item.matches(state, state.searchTerm)) add(item);
162-
}
162+
return _addChildren(decks.map((e) => DeckDefinitionHandItem(item: e)).where(
163+
(e) => e.matches(state, state.searchTerm),
164+
));
163165
}
164166

165-
void _addFigures(ClientWorldState state,
167+
Future<void> _addFigures(ClientWorldState state,
166168
Iterable<(PackItem<FigureDefinition>, String?)> figures) {
167-
for (final figure in figures) {
168-
final item = FigureDefinitionHandItem(item: figure);
169-
if (item.matches(state, state.searchTerm)) add(item);
170-
}
169+
return _addChildren(figures
170+
.map((e) => FigureDefinitionHandItem(item: e))
171+
.where((e) => e.matches(state, state.searchTerm)));
171172
}
172173

173-
void _buildDeckHand(ClientWorldState state, PackItem<DeckDefinition> deck,
174-
bool showDuplicates) {
174+
Future<void> _buildDeckHand(ClientWorldState state,
175+
PackItem<DeckDefinition> deck, bool showDuplicates) {
175176
Iterable<FigureDeckDefinition> deckFigures = deck.item.figures;
176177
Iterable<BoardDeckDefinition> boards = deck.item.boards;
177178
if (!showDuplicates) {
@@ -195,27 +196,37 @@ class GameHand extends CustomPainterComponent
195196
},
196197
);
197198
}
198-
for (final board in deck.item.boards) {
199-
final definition = deck.pack.getBoardItem(board.name, deck.namespace);
200-
if (definition == null) continue;
201-
add(BoardDefinitionHandItem(item: definition));
202-
}
203-
final figures = deckFigures.map((e) {
204-
final figure = deck.pack.getFigureItem(e.name, deck.namespace);
205-
if (figure == null) return null;
206-
return (figure, e.variation);
207-
}).nonNulls;
208-
_addFigures(state, figures);
199+
return Future.wait([
200+
_addFigures(
201+
state,
202+
deckFigures.map((e) {
203+
final figure = deck.pack.getFigureItem(e.name, deck.namespace);
204+
if (figure == null) return null;
205+
return (figure, e.variation);
206+
}).nonNulls),
207+
_addChildren(
208+
boards
209+
.map((e) => deck.pack.getBoardItem(e.name, deck.namespace))
210+
.nonNulls
211+
.map((e) => BoardDefinitionHandItem(item: e))
212+
.where((e) => e.matches(state, state.searchTerm)),
213+
),
214+
]);
209215
}
210216

211-
void _buildCellHand(VectorDefinition location, TableCell? cell) {
212-
for (final tile in cell?.tiles.asMap().entries ?? const Iterable.empty()) {
213-
add(BoardTileHandItem(item: (location, tile.key, tile.value)));
214-
}
215-
for (final object
216-
in cell?.objects.asMap().entries ?? const Iterable.empty()) {
217-
add(GameObjectHandItem(item: (location, object.key, object.value)));
218-
}
217+
Future<void> _buildCellHand(VectorDefinition location, TableCell? cell) {
218+
return Future.wait([
219+
_addChildren(
220+
cell?.objects.asMap().entries.map(
221+
(e) => GameObjectHandItem(item: (location, e.key, e.value))) ??
222+
const Iterable.empty(),
223+
),
224+
_addChildren(
225+
cell?.tiles.asMap().entries.map(
226+
(e) => BoardTileHandItem(item: (location, e.key, e.value))) ??
227+
const Iterable.empty(),
228+
),
229+
]);
219230
}
220231

221232
bool get isShowing => bloc.state.showHand;
@@ -267,14 +278,14 @@ class GameHand extends CustomPainterComponent
267278
super.onDragEnd(event);
268279
}
269280

270-
void dragScroll(double delta) => scroll(delta * -0.025);
281+
void dragScroll(double delta) => scroll(delta * 0.025);
271282

272283
void scroll(double delta) {
273284
if (!isShowing) return;
274-
_currentScroll = (_currentScroll + delta).clamp(0, children.length - 1);
285+
_currentScroll = (_currentScroll - delta).clamp(0, children.length - 1);
275286
_needsLayout = true;
276287
}
277288

278-
void moveLeft() => scroll(-1);
279-
void moveRight() => scroll(1);
289+
void moveLeft() => scroll(1);
290+
void moveRight() => scroll(-1);
280291
}

app/pubspec.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ packages:
165165
dependency: transitive
166166
description:
167167
name: checked_yaml
168-
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
168+
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
169169
url: "https://pub.dev"
170170
source: hosted
171-
version: "2.0.3"
171+
version: "2.0.4"
172172
clock:
173173
dependency: transitive
174174
description:

docs/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
"@astrojs/starlight": "^0.34.3",
1616
"@phosphor-icons/react": "^2.1.10",
1717
"@types/react": "^19.1.6",
18-
"@types/react-dom": "^19.1.5",
19-
"astro": "^5.8.1",
18+
"@types/react-dom": "^19.1.6",
19+
"astro": "^5.8.2",
2020
"react": "^19.1.0",
2121
"react-dom": "^19.1.0",
2222
"remark-gemoji": "^8.0.0",

0 commit comments

Comments
 (0)