Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve board interactions with a custom gesture detector #37

Merged
merged 14 commits into from
Jul 5, 2024
Merged
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 3.0.0

Improve board interaction and add support for drawing shapes while playing.

### Playing:
- pieces are now moved with pointer down events, instead of a tap events
(pointer down followed by a pointer up event): this allows to move a piece
faster
- premoves are not anymore cleared when selecting another piece: this matches lichess website behaviour and allow to prepare another move along with the premove that is currently set

### Drawing shapes (experimental)
- drawing shapes is now possible while keeping the normal board play interaction (before it was either one or another mode)
- one can draw a shape by holding a finger to an empty square while using a second finger to draw a shape anywhere in the board
- a double tap on an empty square will clear all shapes at once
- to clear a single shape is still supported: draw the same shape again

## 2.6.4

- Fix coordinates and board display on devices with RightToLeft Directionality.
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ chess logic so you can use it with different chess variants.
- board themes
- piece sets from lichess
- promotion selector
- draw shapes on board
- draw shapes on board while playing using 2 fingers
- move annotations
- opponent's pieces can be displayed upside down

Expand Down Expand Up @@ -70,5 +70,6 @@ class _MyHomePageState extends State<MyHomePage> {
See the example app for:
- Random Bot: an interactable board for one player playing against a random bot,
- Free Play: an interactable board for two players sitting opposite to each other,
- Draw Shapes: activate the draw shapes feature and draw on the board using 2
- Board Thumbnails: a demo screen showing over hundred different boards in a grid,
- Draw Shapes: a demo screen where the user can highlight squares and draw arrows on a board.
fingers.
2 changes: 1 addition & 1 deletion example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import UIKit
import Flutter

@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
Expand Down
146 changes: 0 additions & 146 deletions example/lib/draw_shapes.dart

This file was deleted.

115 changes: 78 additions & 37 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:chessground/chessground.dart' hide BoardTheme;
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:dartchess/dartchess.dart' as dc;

import 'board_theme.dart';
import 'board_thumbnails.dart';
import 'draw_shapes.dart';

void main() {
runApp(const MyApp());
Expand Down Expand Up @@ -54,9 +52,12 @@ class _HomePageState extends State<HomePage> {
Side sideToMove = Side.white;
PieceSet pieceSet = PieceSet.merida;
BoardTheme boardTheme = BoardTheme.blue;
bool immersiveMode = false;
bool drawMode = true;
bool pieceAnimation = true;
bool dragMagnify = true;
Mode playMode = Mode.botPlay;
dc.Position<dc.Chess>? lastPos;
ISet<Shape> shapes = ISet();

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -103,17 +104,6 @@ class _HomePageState extends State<HomePage> {
);
},
),
ListTile(
title: const Text('Draw Shapes'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DrawShapesPage(),
),
);
},
),
],
)),
body: Center(
Expand All @@ -126,6 +116,19 @@ class _HomePageState extends State<HomePage> {
pieceAssets: pieceSet.assets,
colorScheme: boardTheme.colors,
enableCoordinates: true,
animationDuration: pieceAnimation
? const Duration(milliseconds: 200)
: Duration.zero,
dragFeedbackSize: dragMagnify ? 2.0 : 1.0,
drawShape: DrawShapeOptions(
enable: drawMode,
onCompleteShape: _onCompleteShape,
onClearShapes: () {
setState(() {
shapes = ISet();
});
},
),
),
data: BoardData(
interactableSide: playMode == Mode.botPlay
Expand All @@ -142,6 +145,7 @@ class _HomePageState extends State<HomePage> {
position.turn == dc.Side.white ? Side.white : Side.black,
isCheck: position.isCheck,
premove: premove,
shapes: shapes.isNotEmpty ? shapes : null,
),
onMove: playMode == Mode.botPlay
? _onUserMoveAgainstBot
Expand All @@ -151,29 +155,53 @@ class _HomePageState extends State<HomePage> {
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
child:
Text("Immersive mode: ${immersiveMode ? 'ON' : 'OFF'}"),
onPressed: () {
setState(() {
immersiveMode = !immersiveMode;
});
if (immersiveMode) {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.immersiveSticky);
} else {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.edgeToEdge);
}
},
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
ElevatedButton(
child: Text('Orientation: ${orientation.name}'),
onPressed: () {
setState(() {
orientation = orientation.opposite;
});
},
),
const SizedBox(width: 8),
ElevatedButton(
child:
Text("Magnify drag: ${dragMagnify ? 'ON' : 'OFF'}"),
onPressed: () {
setState(() {
dragMagnify = !dragMagnify;
});
},
),
],
),
ElevatedButton(
child: Text('Orientation: ${orientation.name}'),
onPressed: () {
setState(() {
orientation = orientation.opposite;
});
},
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
ElevatedButton(
child: Text("Drawing mode: ${drawMode ? 'ON' : 'OFF'}"),
onPressed: () {
setState(() {
drawMode = !drawMode;
});
},
),
const SizedBox(width: 8),
ElevatedButton(
child: Text(
"Piece animation: ${pieceAnimation ? 'ON' : 'OFF'}"),
onPressed: () {
setState(() {
pieceAnimation = !pieceAnimation;
});
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
Expand Down Expand Up @@ -235,6 +263,19 @@ class _HomePageState extends State<HomePage> {
);
}

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

void _showChoicesPicker<T extends Enum>(
BuildContext context, {
required List<T> choices,
Expand Down Expand Up @@ -314,7 +355,7 @@ class _HomePageState extends State<HomePage> {
});
if (!position.isGameOver) {
final random = Random();
await Future.delayed(Duration(milliseconds: random.nextInt(5500) + 500));
await Future.delayed(Duration(milliseconds: random.nextInt(1000) + 500));
final allMoves = [
for (final entry in position.legalMoves.entries)
for (final dest in entry.value.squares)
Expand Down
Loading
Loading