Skip to content

Commit

Permalink
Merge pull request #833 from lichess-org/faster_board_draw_mode
Browse files Browse the repository at this point in the history
Update board gesture detector and enable drawing mode
  • Loading branch information
veloce authored Jul 5, 2024
2 parents 604d720 + 1112366 commit 336c560
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 78 deletions.
123 changes: 76 additions & 47 deletions lib/src/view/analysis/analysis_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class _Body extends ConsumerWidget {
}
}

class _Board extends ConsumerWidget {
class _Board extends ConsumerStatefulWidget {
const _Board(
this.pgn,
this.options,
Expand All @@ -371,8 +371,15 @@ class _Board extends ConsumerWidget {
final bool isTablet;

@override
Widget build(BuildContext context, WidgetRef ref) {
final ctrlProvider = analysisControllerProvider(pgn, options);
ConsumerState<_Board> createState() => _BoardState();
}

class _BoardState extends ConsumerState<_Board> {
ISet<cg.Shape> userShapes = ISet();

@override
Widget build(BuildContext context) {
final ctrlProvider = analysisControllerProvider(widget.pgn, widget.options);
final analysisState = ref.watch(ctrlProvider);
final boardPrefs = ref.watch(boardPreferencesProvider);
final showBestMoveArrow = ref.watch(
Expand All @@ -392,8 +399,46 @@ class _Board extends ConsumerWidget {

final sanMove = currentNode.sanMove;

final ISet<cg.Shape> bestMoveShapes = showBestMoveArrow &&
analysisState.isEngineAvailable &&
bestMoves != null
? ISet(
bestMoves.where((move) => move != null).mapIndexed(
(i, move) {
switch (move!) {
case NormalMove(from: _, to: _, promotion: final promRole):
return [
cg.Arrow(
color:
const Color(0x40003088).withOpacity(0.4 - 0.15 * i),
orig: move.cg.from,
dest: move.cg.to,
),
if (promRole != null)
cg.PieceShape(
color: const Color(0x40003088)
.withOpacity(0.4 - 0.15 * i),
orig: move.cg.to,
role: promRole.cg,
),
];
case DropMove(role: final role, to: _):
return [
cg.PieceShape(
color:
const Color(0x40003088).withOpacity(0.4 - 0.15 * i),
orig: move.cg.to,
role: role.cg,
),
];
}
},
).expand((e) => e),
)
: ISet();

return cg.Board(
size: boardSize,
size: widget.boardSize,
onMove: (move, {isDrop, isPremove}) =>
ref.read(ctrlProvider.notifier).onUserMove(Move.fromUci(move.uci)!),
data: cg.BoardData(
Expand All @@ -408,47 +453,7 @@ class _Board extends ConsumerWidget {
lastMove: analysisState.lastMove?.cg,
sideToMove: analysisState.position.turn.cg,
validMoves: analysisState.validMoves,
shapes: showBestMoveArrow &&
analysisState.isEngineAvailable &&
bestMoves != null
? ISet(
bestMoves.where((move) => move != null).mapIndexed(
(i, move) {
switch (move!) {
case NormalMove(
from: _,
to: _,
promotion: final promRole
):
return [
cg.Arrow(
color: const Color(0x40003088)
.withOpacity(0.4 - 0.15 * i),
orig: move.cg.from,
dest: move.cg.to,
),
if (promRole != null)
cg.PieceShape(
color: const Color(0x40003088)
.withOpacity(0.4 - 0.15 * i),
orig: move.cg.to,
role: promRole.cg,
),
];
case DropMove(role: final role, to: _):
return [
cg.PieceShape(
color: const Color(0x40003088)
.withOpacity(0.4 - 0.15 * i),
orig: move.cg.to,
role: role.cg,
),
];
}
},
).expand((e) => e),
)
: null,
shapes: userShapes.union(bestMoveShapes),
annotations: sanMove != null && annotation != null
? altCastles.containsKey(sanMove.move.uci)
? IMap({
Expand All @@ -465,13 +470,37 @@ class _Board extends ConsumerWidget {
showLastMove: boardPrefs.boardHighlights,
enableCoordinates: boardPrefs.coordinates,
animationDuration: boardPrefs.pieceAnimationDuration,
borderRadius: isTablet
borderRadius: widget.isTablet
? const BorderRadius.all(Radius.circular(4.0))
: BorderRadius.zero,
boxShadow: isTablet ? boardShadows : const <BoxShadow>[],
boxShadow: widget.isTablet ? boardShadows : const <BoxShadow>[],
drawShape: cg.DrawShapeOptions(
enable: true,
onCompleteShape: _onCompleteShape,
onClearShapes: _onClearShapes,
),
),
);
}

void _onCompleteShape(cg.Shape shape) {
if (userShapes.any((element) => element == shape)) {
setState(() {
userShapes = userShapes.remove(shape);
});
return;
} else {
setState(() {
userShapes = userShapes.add(shape);
});
}
}

void _onClearShapes() {
setState(() {
userShapes = ISet();
});
}
}

class _EngineGaugeVertical extends ConsumerWidget {
Expand Down
89 changes: 61 additions & 28 deletions lib/src/widgets/board_table.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:chessground/chessground.dart' hide BoardTheme;
import 'package:collection/collection.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Expand All @@ -25,7 +26,7 @@ const _moveListOpacity = 0.6;
/// An optional move list can be displayed above the top table space.
///
/// An optional overlay or error message can be displayed on top of the board.
class BoardTable extends ConsumerWidget {
class BoardTable extends ConsumerStatefulWidget {
const BoardTable({
this.onMove,
this.onPremove,
Expand Down Expand Up @@ -91,7 +92,14 @@ class BoardTable extends ConsumerWidget {
final bool showEngineGaugePlaceholder;

@override
Widget build(BuildContext context, WidgetRef ref) {
ConsumerState<BoardTable> createState() => _BoardTableState();
}

class _BoardTableState extends ConsumerState<BoardTable> {
ISet<Shape> userShapes = ISet();

@override
Widget build(BuildContext context) {
final boardPrefs = ref.watch(boardPreferencesProvider);

return LayoutBuilder(
Expand All @@ -108,7 +116,7 @@ class BoardTable extends ConsumerWidget {
final verticalSpaceLeftBoardOnPortrait =
constraints.biggest.height - boardSize;

final error = errorMessage != null
final error = widget.errorMessage != null
? SizedBox.square(
dimension: boardSize,
child: Center(
Expand All @@ -125,7 +133,7 @@ class BoardTable extends ConsumerWidget {
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(errorMessage!),
child: Text(widget.errorMessage!),
),
),
),
Expand All @@ -144,24 +152,29 @@ class BoardTable extends ConsumerWidget {
? const BorderRadius.all(Radius.circular(4.0))
: BorderRadius.zero,
boxShadow: isTablet ? boardShadows : const <BoxShadow>[],
drawShape: DrawShapeOptions(
enable: true,
onCompleteShape: _onCompleteShape,
onClearShapes: _onClearShapes,
),
);

final settings = boardSettingsOverrides != null
? boardSettingsOverrides!.merge(defaultSettings)
final settings = widget.boardSettingsOverrides != null
? widget.boardSettingsOverrides!.merge(defaultSettings)
: defaultSettings;

final board = Board(
key: boardKey,
key: widget.boardKey,
size: boardSize,
data: boardData,
data: widget.boardData,
settings: settings,
onMove: onMove,
onPremove: onPremove,
onMove: widget.onMove,
onPremove: widget.onPremove,
);

Widget boardWidget = board;

if (boardOverlay != null) {
if (widget.boardOverlay != null) {
boardWidget = SizedBox.square(
dimension: boardSize,
child: Stack(
Expand All @@ -173,7 +186,7 @@ class BoardTable extends ConsumerWidget {
child: SizedBox(
width: (boardSize / 8) * 6.6,
height: (boardSize / 8) * 4.6,
child: boardOverlay,
child: widget.boardOverlay,
),
),
),
Expand All @@ -192,7 +205,7 @@ class BoardTable extends ConsumerWidget {
);
}

final slicedMoves = moves?.asMap().entries.slices(2);
final slicedMoves = widget.moves?.asMap().entries.slices(2);

return aspectRatio > 1
? Row(
Expand All @@ -207,12 +220,12 @@ class BoardTable extends ConsumerWidget {
child: Row(
children: [
boardWidget,
if (engineGauge != null)
if (widget.engineGauge != null)
EngineGauge(
params: engineGauge!,
params: widget.engineGauge!,
displayMode: EngineGaugeDisplayMode.vertical,
)
else if (showEngineGaugePlaceholder)
else if (widget.showEngineGaugePlaceholder)
const SizedBox(width: kEvalGaugeSize),
],
),
Expand All @@ -226,16 +239,17 @@ class BoardTable extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(child: topTable),
Flexible(child: widget.topTable),
if (slicedMoves != null)
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: MoveList(
type: MoveListType.stacked,
slicedMoves: slicedMoves,
currentMoveIndex: currentMoveIndex ?? 0,
onSelectMove: onSelectMove,
currentMoveIndex:
widget.currentMoveIndex ?? 0,
onSelectMove: widget.onSelectMove,
),
),
)
Expand All @@ -247,7 +261,7 @@ class BoardTable extends ConsumerWidget {
child: SizedBox(height: 40),
),
),
Flexible(child: bottomTable),
Flexible(child: widget.bottomTable),
],
),
),
Expand All @@ -263,10 +277,10 @@ class BoardTable extends ConsumerWidget {
MoveList(
type: MoveListType.inline,
slicedMoves: slicedMoves,
currentMoveIndex: currentMoveIndex ?? 0,
onSelectMove: onSelectMove,
currentMoveIndex: widget.currentMoveIndex ?? 0,
onSelectMove: widget.onSelectMove,
)
else if (showMoveListPlaceholder &&
else if (widget.showMoveListPlaceholder &&
verticalSpaceLeftBoardOnPortrait >= 130)
const SizedBox(height: 40),
Expanded(
Expand All @@ -275,22 +289,22 @@ class BoardTable extends ConsumerWidget {
horizontal:
isTablet ? kTabletBoardTableSidePadding : 12.0,
),
child: topTable,
child: widget.topTable,
),
),
if (engineGauge != null)
if (widget.engineGauge != null)
Padding(
padding: isTablet
? const EdgeInsets.symmetric(
horizontal: kTabletBoardTableSidePadding,
)
: EdgeInsets.zero,
child: EngineGauge(
params: engineGauge!,
params: widget.engineGauge!,
displayMode: EngineGaugeDisplayMode.horizontal,
),
)
else if (showEngineGaugePlaceholder)
else if (widget.showEngineGaugePlaceholder)
const SizedBox(height: kEvalGaugeSize),
boardWidget,
Expanded(
Expand All @@ -299,14 +313,33 @@ class BoardTable extends ConsumerWidget {
horizontal:
isTablet ? kTabletBoardTableSidePadding : 12.0,
),
child: bottomTable,
child: widget.bottomTable,
),
),
],
);
},
);
}

void _onCompleteShape(Shape shape) {
if (userShapes.any((element) => element == shape)) {
setState(() {
userShapes = userShapes.remove(shape);
});
return;
} else {
setState(() {
userShapes = userShapes.add(shape);
});
}
}

void _onClearShapes() {
setState(() {
userShapes = ISet();
});
}
}

class BoardSettingsOverrides {
Expand Down
Loading

0 comments on commit 336c560

Please sign in to comment.