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
6 changes: 3 additions & 3 deletions lib/src/model/analysis/analysis_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import 'package:lichess_mobile/src/model/common/uci.dart';
import 'package:lichess_mobile/src/model/engine/evaluation_mixin.dart';
import 'package:lichess_mobile/src/model/engine/evaluation_preferences.dart';
import 'package:lichess_mobile/src/model/engine/evaluation_service.dart';
import 'package:lichess_mobile/src/model/game/archived_game.dart';
import 'package:lichess_mobile/src/model/game/exported_game.dart';
import 'package:lichess_mobile/src/model/game/game_repository_providers.dart';
import 'package:lichess_mobile/src/model/game/player.dart';
import 'package:lichess_mobile/src/network/connectivity.dart';
Expand Down Expand Up @@ -106,7 +106,7 @@ class AnalysisController extends _$AnalysisController
late final ({PlayerAnalysis white, PlayerAnalysis black})? serverAnalysis;
late final Division? division;

ArchivedGame? archivedGame;
ExportedGame? archivedGame;

if (options.gameId != null) {
archivedGame = await ref.watch(archivedGameProvider(id: options.gameId!).future);
Expand Down Expand Up @@ -643,7 +643,7 @@ class AnalysisState with _$AnalysisState implements EvaluationMixinState {
required GameId? gameId,

/// The archived game if it's a finished lichess game.
ArchivedGame? archivedGame,
ExportedGame? archivedGame,

/// The variant of the analysis.
required Variant variant,
Expand Down
5 changes: 4 additions & 1 deletion lib/src/model/common/socket.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ class SocketEvent with _$SocketEvent {
required String topic,
dynamic data,

/// Raw json data of the event.
Map<String, dynamic>? json,

/// Version of the socket event, only for versioned socket routes.
int? version,
}) = _SocketEvent;
Expand All @@ -34,6 +37,6 @@ class SocketEvent with _$SocketEvent {
data: {'nbPlayers': json['d'] as int, 'nbGames': json['r'] as int},
);
}
return SocketEvent(topic: topic, data: json['d'], version: json['v'] as int?);
return SocketEvent(topic: topic, json: json, data: json['d'], version: json['v'] as int?);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,29 @@ import 'package:lichess_mobile/src/model/game/player.dart';
import 'package:lichess_mobile/src/model/user/user.dart';
import 'package:lichess_mobile/src/utils/json.dart';

part 'archived_game.freezed.dart';
part 'archived_game.g.dart';
part 'exported_game.freezed.dart';
part 'exported_game.g.dart';

typedef ClockData = ({Duration initial, Duration increment});

/// A lichess game exported from the API.
/// A lichess game fetched from the export API.
///
/// This represents a game that is finished and can be viewed by anyone, or accessed
/// This usually represents a game that is finished and can be viewed by anyone, or accessed
/// offline.
/// It can also be an ongoing game that is not owned by the current user (e.g. a game of
/// a friend you're watching).
///
/// See also [PlayableGame] for a game owned by the current user and that can be
/// played unless finished.
/// See [PlayableGame] for a game owned by the current user and that can be played unless finished.
@Freezed(fromJson: true, toJson: true)
class ArchivedGame with _$ArchivedGame, BaseGame, IndexableSteps implements BaseGame {
const ArchivedGame._();
class ExportedGame with _$ExportedGame, BaseGame, IndexableSteps implements BaseGame {
const ExportedGame._();

@Assert('steps.isNotEmpty')
factory ArchivedGame({
factory ExportedGame({
required GameId id,
required GameMeta meta,
// TODO refactor to not include this field
required LightArchivedGame data,
required LightExportedGame data,
@JsonKey(fromJson: stepsFromJson, toJson: stepsToJson) required IList<GameStep> steps,
String? initialFen,
required GameStatus status,
Expand All @@ -51,34 +52,34 @@ class ArchivedGame with _$ArchivedGame, BaseGame, IndexableSteps implements Base
required Player black,
IList<ExternalEval>? evals,
IList<Duration>? clocks,
}) = _ArchivedGame;
}) = _ExportedGame;

/// Create an archived game from the lichess api.
///
/// Currently, those endpoints are supported:
/// - GET /game/export/:id
factory ArchivedGame.fromServerJson(Map<String, dynamic> json, {bool withBookmarked = false}) {
factory ExportedGame.fromServerJson(Map<String, dynamic> json, {bool withBookmarked = false}) {
return _archivedGameFromPick(pick(json).required(), withBookmarked: withBookmarked);
}

/// Create an archived game from a local storage JSON.
factory ArchivedGame.fromJson(Map<String, dynamic> json) => _$ArchivedGameFromJson(json);
factory ExportedGame.fromJson(Map<String, dynamic> json) => _$ExportedGameFromJson(json);
}

/// A [LightArchivedGame] associated with a point of view of a player.
typedef LightArchivedGameWithPov = ({LightArchivedGame game, Side pov});
/// A [LightExportedGame] associated with a point of view of a player.
typedef LightExportedGameWithPov = ({LightExportedGame game, Side pov});

/// A lichess game exported from the API, with less data than [ArchivedGame].
/// A lichess game exported from the API, with less data than [ExportedGame].
///
/// This is commonly used to display a list of games.
/// Lichess endpoints that return this data:
/// - GET /api/games/user/:userId
/// - GET /api/games/export/_ids
@Freezed(fromJson: true, toJson: true)
class LightArchivedGame with _$LightArchivedGame {
const LightArchivedGame._();
class LightExportedGame with _$LightExportedGame {
const LightExportedGame._();

const factory LightArchivedGame({
const factory LightExportedGame({
required GameId id,

/// If the full game id is available, it means this is a game owned by the
Expand All @@ -101,9 +102,9 @@ class LightArchivedGame with _$LightArchivedGame {
Side? winner,
ClockData? clock,
bool? bookmarked,
}) = _ArchivedGameData;
}) = _ExportedGameData;

factory LightArchivedGame.fromServerJson(
factory LightExportedGame.fromServerJson(
Map<String, dynamic> json, {

/// Whether to ask the server if the game is bookmarked
Expand All @@ -112,15 +113,15 @@ class LightArchivedGame with _$LightArchivedGame {
/// Whether it is already known that the game is bookmarked
bool isBookmarked = false,
}) {
return _lightArchivedGameFromPick(
return _lightExportedGameFromPick(
pick(json).required(),
withBookmarked: withBookmarked,
isBookmarked: isBookmarked,
);
}

factory LightArchivedGame.fromJson(Map<String, dynamic> json) =>
_$LightArchivedGameFromJson(json);
factory LightExportedGame.fromJson(Map<String, dynamic> json) =>
_$LightExportedGameFromJson(json);

bool get isBookmarked => bookmarked == true;

Expand All @@ -145,16 +146,16 @@ IList<ExternalEval>? gameEvalsFromPick(RequiredPick pick) {
?.lock;
}

ArchivedGame _archivedGameFromPick(RequiredPick pick, {bool withBookmarked = false}) {
final data = _lightArchivedGameFromPick(pick, withBookmarked: withBookmarked);
ExportedGame _archivedGameFromPick(RequiredPick pick, {bool withBookmarked = false}) {
final data = _lightExportedGameFromPick(pick, withBookmarked: withBookmarked);
final clocks = pick(
'clocks',
).asListOrNull<Duration>((p0) => Duration(milliseconds: p0.asIntOrThrow() * 10));
final division = pick('division').letOrNull(_divisionFromPick);

final initialFen = pick('initialFen').asStringOrNull();

return ArchivedGame(
return ExportedGame(
id: data.id,
meta: GameMeta(
createdAt: data.createdAt,
Expand Down Expand Up @@ -185,7 +186,9 @@ ArchivedGame _archivedGameFromPick(RequiredPick pick, {bool withBookmarked = fal
white: data.white,
black: data.black,
steps: pick('moves').letOrThrow((it) {
final moves = it.asStringOrThrow().split(' ');
final moves = it.asStringOrThrow();
final movesList = moves.isEmpty ? <String>[] : moves.split(' ');

// assume lichess always send initialFen with fromPosition and chess960
Position position =
(data.variant == Variant.fromPosition || data.variant == Variant.chess960)
Expand All @@ -194,7 +197,7 @@ ArchivedGame _archivedGameFromPick(RequiredPick pick, {bool withBookmarked = fal
int index = 0;
final List<GameStep> steps = [GameStep(position: position)];
Duration? clock = data.clock?.initial;
for (final san in moves) {
for (final san in movesList) {
final stepClock = clocks?[index];
index++;
final move = position.parseSan(san);
Expand All @@ -218,12 +221,12 @@ ArchivedGame _archivedGameFromPick(RequiredPick pick, {bool withBookmarked = fal
);
}

LightArchivedGame _lightArchivedGameFromPick(
LightExportedGame _lightExportedGameFromPick(
RequiredPick pick, {
bool withBookmarked = false,
bool isBookmarked = false,
}) {
return LightArchivedGame(
return LightExportedGame(
id: pick('id').asGameIdOrThrow(),
fullId: pick('fullId').asGameFullIdOrNull(),
source: pick(
Expand Down
8 changes: 4 additions & 4 deletions lib/src/model/game/game_bookmarks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:lichess_mobile/src/model/auth/auth_session.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/exported_game.dart';
import 'package:lichess_mobile/src/model/game/game_repository.dart';
import 'package:lichess_mobile/src/network/http.dart';
import 'package:result_extensions/result_extensions.dart';
Expand All @@ -21,7 +21,7 @@ const _nbPerPage = 20;
/// A provider that paginates the game bookmarks for the current app user.
@riverpod
class GameBookmarksPaginator extends _$GameBookmarksPaginator {
final _list = <LightArchivedGameWithPov>[];
final _list = <LightExportedGameWithPov>[];

@override
Future<GameBookmarksPaginatorState> build() async {
Expand All @@ -33,7 +33,7 @@ class GameBookmarksPaginator extends _$GameBookmarksPaginator {

if (session == null) {
return GameBookmarksPaginatorState(
gameList: <LightArchivedGameWithPov>[].toIList(),
gameList: <LightExportedGameWithPov>[].toIList(),
isLoading: false,
hasMore: false,
hasError: false,
Expand Down Expand Up @@ -107,7 +107,7 @@ class GameBookmarksPaginator extends _$GameBookmarksPaginator {
@freezed
class GameBookmarksPaginatorState with _$GameBookmarksPaginatorState {
const factory GameBookmarksPaginatorState({
required IList<LightArchivedGameWithPov> gameList,
required IList<LightExportedGameWithPov> gameList,
required bool isLoading,
required bool hasMore,
required bool hasError,
Expand Down
8 changes: 4 additions & 4 deletions lib/src/model/game/game_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import 'package:lichess_mobile/src/model/common/service/sound_service.dart';
import 'package:lichess_mobile/src/model/common/socket.dart';
import 'package:lichess_mobile/src/model/common/speed.dart';
import 'package:lichess_mobile/src/model/correspondence/correspondence_service.dart';
import 'package:lichess_mobile/src/model/game/archived_game.dart';
import 'package:lichess_mobile/src/model/game/exported_game.dart';
import 'package:lichess_mobile/src/model/game/game.dart';
import 'package:lichess_mobile/src/model/game/game_repository.dart';
import 'package:lichess_mobile/src/model/game/game_socket_events.dart';
Expand Down Expand Up @@ -888,11 +888,11 @@ class GameController extends _$GameController {
final gameStorage = await ref.read(gameStorageProvider.future);
final existing = await gameStorage.fetch(gameId: gameFullId.gameId);
final finishedAt = existing?.data.lastMoveAt ?? DateTime.now();
await gameStorage.save(game.toArchivedGame(finishedAt: finishedAt));
await gameStorage.save(game.toExportedGame(finishedAt: finishedAt));
}
}

FutureResult<ArchivedGame> _getPostGameData() {
FutureResult<ExportedGame> _getPostGameData() {
return Result.capture(
ref.withClient((client) => GameRepository(client).getGame(gameFullId.gameId)),
);
Expand All @@ -918,7 +918,7 @@ class GameController extends _$GameController {

PlayableGame _mergePostGameData(
PlayableGame game,
ArchivedGame data, {
ExportedGame data, {

/// Whether to rewrite the steps with the clock data from the archived game
///
Expand Down
10 changes: 5 additions & 5 deletions lib/src/model/game/game_history.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:lichess_mobile/src/model/account/account_repository.dart';
import 'package:lichess_mobile/src/model/auth/auth_session.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/exported_game.dart';
import 'package:lichess_mobile/src/model/game/game_filter.dart';
import 'package:lichess_mobile/src/model/game/game_repository.dart';
import 'package:lichess_mobile/src/model/game/game_storage.dart';
Expand All @@ -35,7 +35,7 @@ const _nbPerPage = 20;
/// If the user is not logged in, or there is no connectivity, the recent games
/// stored locally are fetched instead.
@riverpod
Future<IList<LightArchivedGameWithPov>> myRecentGames(Ref ref) async {
Future<IList<LightExportedGameWithPov>> myRecentGames(Ref ref) async {
final online = await ref.watch(connectivityChangesProvider.selectAsync((c) => c.isOnline));
final session = ref.watch(authSessionProvider);
if (session != null && online) {
Expand All @@ -59,7 +59,7 @@ Future<IList<LightArchivedGameWithPov>> myRecentGames(Ref ref) async {

/// A provider that fetches the recent games from the server for a given user.
@riverpod
Future<IList<LightArchivedGameWithPov>> userRecentGames(Ref ref, {required UserId userId}) {
Future<IList<LightExportedGameWithPov>> userRecentGames(Ref ref, {required UserId userId}) {
return ref.withClient(
(client) => GameRepository(client).getUserGames(userId, withBookmarked: true),
);
Expand Down Expand Up @@ -87,7 +87,7 @@ Future<int> userNumberOfGames(Ref ref, LightUser? user) async {
/// Otherwise, the game history is fetched from the local storage.
@riverpod
class UserGameHistory extends _$UserGameHistory {
final _list = <LightArchivedGameWithPov>[];
final _list = <LightExportedGameWithPov>[];

@override
Future<UserGameHistoryState> build(
Expand Down Expand Up @@ -234,7 +234,7 @@ class UserGameHistory extends _$UserGameHistory {
@freezed
class UserGameHistoryState with _$UserGameHistoryState {
const factory UserGameHistoryState({
required IList<LightArchivedGameWithPov> gameList,
required IList<LightExportedGameWithPov> gameList,
required bool isLoading,
required GameFilterState filter,
required bool hasMore,
Expand Down
Loading