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

1043 add castling method option v2 #1347

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
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
28 changes: 26 additions & 2 deletions lib/src/model/game/game_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -954,10 +954,34 @@ class GameState with _$GameState {
}) = _GameState;

/// The [Position] and its legal moves at the current cursor.
(Position, IMap<Square, ISet<Square>>) get currentPosition {
(Position, IMap<Square, ISet<Square>>) getCurrentPosition(CastlingMethod castlingMethod) {
final position = game.positionAt(stepCursor);
final legalMoves = makeLegalMoves(position, isChess960: game.meta.variant == Variant.chess960);
return (position, legalMoves);

final Map<Square, Square> castlingMap = {
Square.a1: Square.c1,
Square.a8: Square.c8,
Square.h1: Square.g1,
Square.h8: Square.g8,
};

MapEntry<Square, ISet<Square>> mapper(Square sq, ISet<Square> moves) {
return MapEntry(
sq,
position.board.kings.squares.contains(sq) && //king move
position.castles.castlingRights.squares.intersectsWith(
moves, //king can castle
)
? (switch (castlingMethod) {
CastlingMethod.kingOverRook => moves.removeAll(castlingMap.values),
CastlingMethod.kingTwoSquares => moves.removeAll(castlingMap.keys),
_ => moves,
})
: moves,
);
}

return (position, legalMoves.map(mapper));
}

/// Whether the zen mode is active
Expand Down
19 changes: 19 additions & 0 deletions lib/src/model/settings/board_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class BoardPreferences extends _$BoardPreferences with PreferencesStorage<BoardP
await save(state.copyWith(pieceShiftMethod: pieceShiftMethod));
}

Future<void> setCastlingMethod(CastlingMethod castlingMethod) {
return save(state.copyWith(castlingMethod: castlingMethod));
}

Future<void> toggleHapticFeedback() {
return save(state.copyWith(hapticFeedback: !state.hapticFeedback));
}
Expand Down Expand Up @@ -125,6 +129,7 @@ class BoardPrefs with _$BoardPrefs implements Serializable {
required ClockPosition clockPosition,
@JsonKey(defaultValue: PieceShiftMethod.either, unknownEnumValue: PieceShiftMethod.either)
required PieceShiftMethod pieceShiftMethod,
required CastlingMethod castlingMethod,

/// Whether to enable shape drawings on the board for games and puzzles.
@JsonKey(defaultValue: true) required bool enableShapeDrawings,
Expand All @@ -150,6 +155,7 @@ class BoardPrefs with _$BoardPrefs implements Serializable {
materialDifferenceFormat: MaterialDifferenceFormat.materialDifference,
clockPosition: ClockPosition.right,
pieceShiftMethod: PieceShiftMethod.either,
castlingMethod: CastlingMethod.either,
enableShapeDrawings: true,
magnifyDraggedPiece: true,
dragTargetKind: DragTargetKind.circle,
Expand Down Expand Up @@ -347,6 +353,19 @@ enum ClockPosition {
};
}

enum CastlingMethod {
kingOverRook,
kingTwoSquares,
either;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not support either because it is not supported on website.

The default is kingOverRook


// TODO: l10n
String get label => switch (this) {
CastlingMethod.kingOverRook => 'Move king over rook',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

translation keys already exist: look at app_en.arb: preferencesCastleByMovingOntoTheRook.

CastlingMethod.kingTwoSquares => 'Move king two squares',
CastlingMethod.either => 'Either',
};
}

String dragTargetKindLabel(DragTargetKind kind) => switch (kind) {
DragTargetKind.circle => 'Circle',
DragTargetKind.square => 'Square',
Expand Down
4 changes: 3 additions & 1 deletion lib/src/view/game/game_body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ class GameBody extends ConsumerWidget {

return gameStateAsync.when(
data: (gameState) {
final (position, legalMoves) = gameState.currentPosition;
final (position, legalMoves) = gameState.getCurrentPosition(
boardPreferences.castlingMethod,
);
final youAre = gameState.game.youAre ?? Side.white;
final archivedBlackClock = gameState.game.archivedBlackClockAt(gameState.stepCursor);
final archivedWhiteClock = gameState.game.archivedWhiteClockAt(gameState.stepCursor);
Expand Down
68 changes: 68 additions & 0 deletions lib/src/view/settings/board_settings_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,34 @@ class _Body extends ConsumerWidget {
}
},
),
SettingsListTile(
settingsLabel: Text(
context.l10n.preferencesCastleByMovingTheKingTwoSquaresOrOntoTheRook,
),
settingsValue: boardPrefs.castlingMethod.name,
showCupertinoTrailingValue: false,
onTap: () {
if (Theme.of(context).platform == TargetPlatform.android) {
showChoicePicker(
context,
choices: CastlingMethod.values,
selectedItem: boardPrefs.castlingMethod,
labelBuilder: (t) => Text(t.label),
onSelectedItemChanged: (CastlingMethod? value) {
ref
.read(boardPreferencesProvider.notifier)
.setCastlingMethod(value ?? CastlingMethod.either);
},
);
} else {
pushPlatformRoute(
context,
title: context.l10n.preferencesCastleByMovingTheKingTwoSquaresOrOntoTheRook,
builder: (context) => const CastlingMethodSettingsScreen(),
);
}
},
),
SwitchSettingTile(
title: Text(context.l10n.mobilePrefMagnifyDraggedPiece),
value: boardPrefs.magnifyDraggedPiece,
Expand Down Expand Up @@ -271,6 +299,38 @@ class PieceShiftMethodSettingsScreen extends ConsumerWidget {
}
}

class CastlingMethodSettingsScreen extends ConsumerWidget {
const CastlingMethodSettingsScreen({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final castlingMethod = ref.watch(
boardPreferencesProvider.select((state) => state.castlingMethod),
);

void onChanged(CastlingMethod? value) {
ref.read(boardPreferencesProvider.notifier).setCastlingMethod(value ?? CastlingMethod.either);
}

return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(),
child: SafeArea(
child: ListView(
children: [
ChoicePicker(
notchedTile: true,
choices: CastlingMethod.values,
selectedItem: castlingMethod,
titleBuilder: (t) => Text(t.label),
onSelectedItemChanged: onChanged,
),
],
),
),
);
}
}

class BoardClockPositionScreen extends ConsumerWidget {
const BoardClockPositionScreen({super.key});

Expand Down Expand Up @@ -369,3 +429,11 @@ String pieceShiftMethodl10n(BuildContext context, PieceShiftMethod pieceShiftMet
PieceShiftMethod.drag => context.l10n.preferencesDragPiece,
PieceShiftMethod.tapTwoSquares => 'Tap two squares',
};

String castlingMethodl10n(BuildContext context, CastlingMethod castlingMethod) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated l10n logic; must be defined directly in the enum to be consistent with rest of code.

switch (castlingMethod) {
// TODO add this to mobile translations
CastlingMethod.kingOverRook => context.l10n.preferencesCastleByMovingOntoTheRook,
CastlingMethod.kingTwoSquares => context.l10n.preferencesCastleByMovingTwoSquares,
CastlingMethod.either => 'Either',
};
Loading