-
-
Notifications
You must be signed in to change notification settings - Fork 310
Over the board feats: Resign, Offer Draw and notification on threefold repetition #1571
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
Changes from all commits
b5d07a4
1d643b2
748683d
1c062a2
0d7925f
1f39e0c
9543b9b
d48d755
de0b10a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,22 +6,27 @@ import 'package:dartchess/dartchess.dart'; | |
| import 'package:flutter/cupertino.dart'; | ||
| import 'package:flutter/material.dart'; | ||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
| import 'package:lichess_mobile/src/model/analysis/analysis_controller.dart'; | ||
| import 'package:lichess_mobile/src/model/over_the_board/over_the_board_clock.dart'; | ||
| import 'package:lichess_mobile/src/model/over_the_board/over_the_board_game_controller.dart'; | ||
| import 'package:lichess_mobile/src/model/settings/board_preferences.dart'; | ||
| import 'package:lichess_mobile/src/model/settings/over_the_board_preferences.dart'; | ||
| import 'package:lichess_mobile/src/utils/immersive_mode.dart'; | ||
| import 'package:lichess_mobile/src/utils/l10n_context.dart'; | ||
| import 'package:lichess_mobile/src/utils/navigation.dart'; | ||
| import 'package:lichess_mobile/src/utils/string.dart'; | ||
| import 'package:lichess_mobile/src/view/analysis/analysis_screen.dart'; | ||
| import 'package:lichess_mobile/src/view/game/game_player.dart'; | ||
| import 'package:lichess_mobile/src/view/game/game_result_dialog.dart'; | ||
| import 'package:lichess_mobile/src/view/over_the_board/configure_over_the_board_game.dart'; | ||
| import 'package:lichess_mobile/src/widgets/adaptive_action_sheet.dart'; | ||
| import 'package:lichess_mobile/src/widgets/board_table.dart'; | ||
| import 'package:lichess_mobile/src/widgets/bottom_bar.dart'; | ||
| import 'package:lichess_mobile/src/widgets/bottom_bar_button.dart'; | ||
| import 'package:lichess_mobile/src/widgets/buttons.dart'; | ||
| import 'package:lichess_mobile/src/widgets/clock.dart'; | ||
| import 'package:lichess_mobile/src/widgets/platform_scaffold.dart'; | ||
| import 'package:lichess_mobile/src/widgets/yes_no_dialog.dart'; | ||
|
|
||
| class OverTheBoardScreen extends StatelessWidget { | ||
| const OverTheBoardScreen({super.key}); | ||
|
|
@@ -95,6 +100,31 @@ class _BodyState extends ConsumerState<_Body> { | |
| } | ||
| }); | ||
| } | ||
|
|
||
| if (previous?.game.isThreefoldRepetition == false && | ||
| newGameState.game.isThreefoldRepetition == true) { | ||
| Timer(const Duration(milliseconds: 500), () { | ||
| if (context.mounted) { | ||
| ref.read(overTheBoardClockProvider.notifier).pause(); | ||
| showAdaptiveDialog<void>( | ||
| context: context, | ||
| builder: | ||
| (context) => YesNoDialog( | ||
| title: Text(context.l10n.threefoldRepetition), | ||
| content: const Text('Accept draw?'), | ||
| onYes: () { | ||
| Navigator.pop(context); | ||
| ref.read(overTheBoardGameControllerProvider.notifier).draw(); | ||
| }, | ||
| onNo: () { | ||
| Navigator.pop(context); | ||
| ref.read(overTheBoardClockProvider.notifier).resume(previous!.turn); | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| return WakelockWidget( | ||
|
|
@@ -183,15 +213,11 @@ class _BottomBar extends ConsumerWidget { | |
| return PlatformBottomBar( | ||
| children: [ | ||
| BottomBarButton( | ||
| label: 'Configure game', | ||
| onTap: () => showConfigureGameSheet(context, isDismissible: true), | ||
| icon: Icons.add, | ||
| ), | ||
| BottomBarButton( | ||
| key: const Key('flip-button'), | ||
| label: context.l10n.flipBoard, | ||
| onTap: onFlipBoard, | ||
| icon: CupertinoIcons.arrow_2_squarepath, | ||
| label: context.l10n.menu, | ||
| onTap: () { | ||
| _showOtbGameMenu(context, ref); | ||
| }, | ||
| icon: Icons.menu, | ||
| ), | ||
| if (!clock.timeIncrement.isInfinite) | ||
| BottomBarButton( | ||
|
|
@@ -241,6 +267,81 @@ class _BottomBar extends ConsumerWidget { | |
| ], | ||
| ); | ||
| } | ||
|
|
||
| Future<void> _showOtbGameMenu(BuildContext context, WidgetRef ref) { | ||
| final gameState = ref.read(overTheBoardGameControllerProvider); | ||
| return showAdaptiveActionSheet( | ||
| context: context, | ||
| actions: [ | ||
| BottomSheetAction( | ||
| makeLabel: (context) => const Text('New game'), | ||
| onPressed: () => showConfigureGameSheet(context, isDismissible: true), | ||
| ), | ||
| if (gameState.game.finished) | ||
| BottomSheetAction( | ||
| makeLabel: (context) => Text(context.l10n.analysis), | ||
| onPressed: | ||
| () => Navigator.of(context).push( | ||
| AnalysisScreen.buildRoute( | ||
| context, | ||
| AnalysisOptions( | ||
| orientation: Side.white, | ||
| standalone: ( | ||
| pgn: gameState.game.makePgn(), | ||
| isComputerAnalysisAllowed: true, | ||
| variant: gameState.game.meta.variant, | ||
| ), | ||
| ), | ||
| ), | ||
| ), | ||
| ), | ||
| BottomSheetAction( | ||
| makeLabel: (context) => Text(context.l10n.flipBoard), | ||
| onPressed: onFlipBoard, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't there already a bottom bar button for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, there is. I'll remove the option from the menu. This will leave the hamburger menu with only one option (New game) at the start of a game, making the menu pointless for that state. However, when the game starts and the Resign and Draw options come into play, the hamburger menu is needed. So if it's fine by you, I'll make the bottom bar button switch between the plus icon and the menu icon as required. Alternatively, we could just leave it as is (regular online games have a resign button in the bottom bar AND in the menu. Also I'm lazy haha) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah that makes sense, got it! I think switching between hamburger/plus icon sounds good, but I'm also ok with leaving it like it is is right now. @veloce has the final word on that as the maintainer, so let's wait for his opinion There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the flip button that important so it needs to be in the bottom bar? Because we can also remove it from the bottom bar. If not I prefer leaving the hamburger menu all the time and not switching between icons. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| ), | ||
| if (gameState.game.drawable) | ||
| BottomSheetAction( | ||
| makeLabel: (context) => Text(context.l10n.offerDraw), | ||
| onPressed: () { | ||
| final offerer = gameState.turn.name.capitalize(); | ||
| showAdaptiveDialog<void>( | ||
| context: context, | ||
| builder: | ||
| (context) => YesNoDialog( | ||
| title: Text('${context.l10n.draw}?'), | ||
| content: Text('$offerer offers draw. Does opponent accept?'), | ||
| onYes: () { | ||
| Navigator.pop(context); | ||
| ref.read(overTheBoardGameControllerProvider.notifier).draw(); | ||
| }, | ||
| onNo: () => Navigator.pop(context), | ||
| ), | ||
| ); | ||
| }, | ||
| ), | ||
| if (gameState.game.resignable) | ||
| BottomSheetAction( | ||
| makeLabel: (context) => Text(context.l10n.resign), | ||
| onPressed: () { | ||
| final offerer = gameState.turn.name.capitalize(); | ||
| showAdaptiveDialog<void>( | ||
| context: context, | ||
| builder: | ||
| (context) => YesNoDialog( | ||
| title: Text('${context.l10n.resign}?'), | ||
| content: Text('Are you sure you want to resign as $offerer?'), | ||
| onYes: () { | ||
| Navigator.pop(context); | ||
| ref.read(overTheBoardGameControllerProvider.notifier).resign(); | ||
| }, | ||
| onNo: () => Navigator.pop(context), | ||
| ), | ||
| ); | ||
| }, | ||
| ), | ||
| ], | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| class _Player extends ConsumerWidget { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.