Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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