Skip to content

Commit

Permalink
Merge pull request #993 from lichess-org/fix_loading_game_from_explorer
Browse files Browse the repository at this point in the history
Fix loading games from explorer
  • Loading branch information
veloce authored Sep 7, 2024
2 parents 609cc71 + d5192d1 commit 910fac2
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 162 deletions.
195 changes: 155 additions & 40 deletions lib/src/view/game/archived_game_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ 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/common/http.dart';
import 'package:lichess_mobile/src/model/common/id.dart';
import 'package:lichess_mobile/src/model/game/archived_game.dart';
import 'package:lichess_mobile/src/model/game/game_repository_providers.dart';
import 'package:lichess_mobile/src/utils/l10n_context.dart';
import 'package:lichess_mobile/src/utils/navigation.dart';
import 'package:lichess_mobile/src/view/analysis/analysis_screen.dart';
Expand All @@ -24,22 +27,112 @@ import 'archived_game_screen_providers.dart';
/// Screen for viewing an archived game.
class ArchivedGameScreen extends ConsumerWidget {
const ArchivedGameScreen({
required this.gameData,
this.gameId,
this.gameData,
required this.orientation,
this.initialCursor,
super.key,
}) : assert(gameId != null || gameData != null);

final LightArchivedGame? gameData;
final GameId? gameId;

final Side orientation;
final int? initialCursor;

@override
Widget build(BuildContext context, WidgetRef ref) {
if (gameData != null) {
return _Body(
gameData: gameData,
orientation: orientation,
initialCursor: initialCursor,
);
} else {
return _LoadGame(
gameId: gameId!,
orientation: orientation,
initialCursor: initialCursor,
);
}
}
}

class _LoadGame extends ConsumerWidget {
const _LoadGame({
required this.gameId,
required this.orientation,
required this.initialCursor,
});

final LightArchivedGame gameData;
final GameId gameId;
final Side orientation;
final int? initialCursor;

@override
Widget build(BuildContext context, WidgetRef ref) {
final game = ref.watch(archivedGameProvider(id: gameId));
return game.when(
data: (game) {
return _Body(
gameData: game.data,
orientation: orientation,
initialCursor: initialCursor,
);
},
loading: () => _Body(
gameData: null,
orientation: orientation,
initialCursor: initialCursor,
),
error: (error, stackTrace) {
debugPrint(
'SEVERE: [ArchivedGameScreen] could not load game; $error\n$stackTrace',
);
switch (error) {
case ServerException _ when error.statusCode == 404:
return _Body(
gameData: null,
orientation: orientation,
initialCursor: initialCursor,
error: 'Game not found.',
);
default:
return _Body(
gameData: null,
orientation: orientation,
initialCursor: initialCursor,
error: error,
);
}
},
);
}
}

class _Body extends StatelessWidget {
const _Body({
required this.gameData,
required this.orientation,
this.initialCursor,
this.error,
});

final LightArchivedGame? gameData;
final Object? error;
final Side orientation;
final int? initialCursor;

@override
Widget build(BuildContext context) {
return PlatformScaffold(
appBar: PlatformAppBar(
title: _GameTitle(gameData: gameData),
title: gameData != null
? _GameTitle(gameData: gameData!)
: const SizedBox.shrink(),
actions: [
if (gameData == null && error == null)
const PlatformAppBarLoadingIndicator(),
ToggleSoundButton(),
],
),
Expand All @@ -49,12 +142,13 @@ class ArchivedGameScreen extends ConsumerWidget {
children: [
Expanded(
child: _BoardBody(
gameData: gameData,
archivedGameData: gameData,
orientation: orientation,
initialCursor: initialCursor,
error: error,
),
),
_BottomBar(gameData: gameData, orientation: orientation),
_BottomBar(archivedGameData: gameData, orientation: orientation),
],
),
),
Expand Down Expand Up @@ -89,17 +183,28 @@ class _GameTitle extends StatelessWidget {

class _BoardBody extends ConsumerWidget {
const _BoardBody({
required this.gameData,
required this.archivedGameData,
required this.orientation,
this.error,
this.initialCursor,
});

final LightArchivedGame gameData;
final LightArchivedGame? archivedGameData;
final Side orientation;
final int? initialCursor;
final Object? error;

@override
Widget build(BuildContext context, WidgetRef ref) {
final gameData = archivedGameData;

if (gameData == null) {
return BoardTable.empty(
showMoveListPlaceholder: true,
errorMessage: error?.toString(),
);
}

if (initialCursor != null) {
ref.listen(gameCursorProvider(gameData.id), (prev, cursor) {
if (prev?.isLoading == true && cursor.hasValue) {
Expand All @@ -124,7 +229,9 @@ class _BoardBody extends ConsumerWidget {
final bottomPlayer = orientation == Side.white ? white : black;
final loadingBoard = BoardTable(
orientation: (isBoardTurned ? orientation.opposite : orientation),
fen: gameData.lastFen ?? kInitialBoardFEN,
fen: initialCursor == null
? gameData.lastFen ?? kEmptyBoardFEN
: kEmptyBoardFEN,
topTable: topPlayer,
bottomTable: bottomPlayer,
showMoveListPlaceholder: true,
Expand Down Expand Up @@ -195,24 +302,53 @@ class _BoardBody extends ConsumerWidget {
}

class _BottomBar extends ConsumerWidget {
const _BottomBar({required this.gameData, required this.orientation});
const _BottomBar({required this.archivedGameData, required this.orientation});

final Side orientation;
final LightArchivedGame gameData;
final LightArchivedGame? archivedGameData;

@override
Widget build(BuildContext context, WidgetRef ref) {
final gameData = archivedGameData;

if (gameData == null) {
return const BottomBar(children: []);
}

final canGoForward = ref.watch(canGoForwardProvider(gameData.id));
final canGoBackward = ref.watch(canGoBackwardProvider(gameData.id));
final gameCursor = ref.watch(gameCursorProvider(gameData.id));

Future<void> showGameMenu() {
final game = gameCursor.valueOrNull?.$1;
final cursor = gameCursor.valueOrNull?.$2;
return showAdaptiveActionSheet(
context: context,
actions: [
BottomSheetAction(
makeLabel: (context) => Text(context.l10n.flipBoard),
onPressed: (context) {
ref.read(isBoardTurnedProvider.notifier).toggle();
},
),
if (game != null && cursor != null)
...makeFinishedGameShareActions(
game,
context: context,
ref: ref,
currentGamePosition: game.positionAt(cursor),
orientation: orientation,
lastMove: game.moveAt(cursor),
),
],
);
}

return BottomBar(
children: [
BottomBarButton(
label: context.l10n.menu,
onTap: () {
_showGameMenu(context, ref);
},
onTap: showGameMenu,
icon: Icons.menu,
),
gameCursor.when(
Expand Down Expand Up @@ -289,35 +425,14 @@ class _BottomBar extends ConsumerWidget {
}

void _cursorForward(WidgetRef ref) {
ref.read(gameCursorProvider(gameData.id).notifier).cursorForward();
if (archivedGameData == null) return;
ref.read(gameCursorProvider(archivedGameData!.id).notifier).cursorForward();
}

void _cursorBackward(WidgetRef ref) {
ref.read(gameCursorProvider(gameData.id).notifier).cursorBackward();
}

Future<void> _showGameMenu(BuildContext context, WidgetRef ref) {
final game = ref.read(gameCursorProvider(gameData.id)).valueOrNull?.$1;
final cursor = ref.read(gameCursorProvider(gameData.id)).valueOrNull?.$2;
return showAdaptiveActionSheet(
context: context,
actions: [
BottomSheetAction(
makeLabel: (context) => Text(context.l10n.flipBoard),
onPressed: (context) {
ref.read(isBoardTurnedProvider.notifier).toggle();
},
),
if (game != null && cursor != null)
...makeFinishedGameShareActions(
game,
context: context,
ref: ref,
currentGamePosition: game.positionAt(cursor),
orientation: orientation,
lastMove: game.moveAt(cursor),
),
],
);
if (archivedGameData == null) return;
ref
.read(gameCursorProvider(archivedGameData!.id).notifier)
.cursorBackward();
}
}
Loading

0 comments on commit 910fac2

Please sign in to comment.