diff --git a/lib/src/model/study/study.dart b/lib/src/model/study/study.dart index 8ff3fa9c1a..792994b79e 100644 --- a/lib/src/model/study/study.dart +++ b/lib/src/model/study/study.dart @@ -1,11 +1,115 @@ +import 'package:collection/collection.dart'; +import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:lichess_mobile/src/model/common/chess.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; part 'study.freezed.dart'; part 'study.g.dart'; +@Freezed(fromJson: true) +class Study with _$Study { + const Study._(); + + const factory Study({ + required StudyId id, + required String name, + required ({StudyChapterId chapterId, String path}) position, + required bool liked, + required int likes, + required UserId? ownerId, + required IList topics, + required IList chapters, + required StudyChapter chapter, + }) = _Study; + + StudyChapterMeta get currentChapterMeta => + chapters.firstWhere((c) => c.id == chapter.id); + + factory Study.fromJson(Map json) => _$StudyFromJson(json); +} + +@Freezed(fromJson: true) +class StudyFeatures with _$StudyFeatures { + const StudyFeatures._(); + + const factory StudyFeatures({ + @JsonKey(defaultValue: false) required bool cloneable, + @JsonKey(defaultValue: false) required bool chat, + @JsonKey(defaultValue: false) required bool sticky, + }) = _StudyFeatures; + + factory StudyFeatures.fromJson(Map json) => + _$StudyFeaturesFromJson(json); +} + +@Freezed(fromJson: true) +class StudyChapter with _$StudyChapter { + const StudyChapter._(); + + const factory StudyChapter({ + required StudyChapterId id, + required StudyChapterSetup setup, + @JsonKey(defaultValue: false) required bool practise, + required int? conceal, + @JsonKey(defaultValue: false) required bool gamebook, + required StudyChapterFeatures features, + }) = _StudyChapter; + + factory StudyChapter.fromJson(Map json) => + _$StudyChapterFromJson(json); +} + +@Freezed(fromJson: true) +class StudyChapterFeatures with _$StudyChapterFeatures { + const StudyChapterFeatures._(); + + const factory StudyChapterFeatures({ + @JsonKey(defaultValue: false) required bool computer, + @JsonKey(defaultValue: false) required bool explorer, + }) = _StudyChapterFeatures; + + factory StudyChapterFeatures.fromJson(Map json) => + _$StudyChapterFeaturesFromJson(json); +} + +@Freezed(fromJson: true) +class StudyChapterSetup with _$StudyChapterSetup { + const StudyChapterSetup._(); + + const factory StudyChapterSetup({ + required GameId? id, + required Side orientation, + @JsonKey(fromJson: _variantFromJson) required Variant variant, + required bool? fromFen, + }) = _StudyChapterSetup; + + factory StudyChapterSetup.fromJson(Map json) => + _$StudyChapterSetupFromJson(json); +} + +Variant _variantFromJson(Map json) { + return Variant.values.firstWhereOrNull( + (v) => v.name == json['key'], + )!; +} + +@Freezed(fromJson: true) +class StudyChapterMeta with _$StudyChapterMeta { + const StudyChapterMeta._(); + + const factory StudyChapterMeta({ + required StudyChapterId id, + required String name, + required String? fen, + }) = _StudyChapterMeta; + + factory StudyChapterMeta.fromJson(Map json) => + _$StudyChapterMetaFromJson(json); +} + @Freezed(fromJson: true) class StudyPageData with _$StudyPageData { const StudyPageData._(); diff --git a/lib/src/model/study/study_repository.dart b/lib/src/model/study/study_repository.dart index b0e6b84461..5b479a7ef7 100644 --- a/lib/src/model/study/study_repository.dart +++ b/lib/src/model/study/study_repository.dart @@ -1,6 +1,9 @@ +import 'dart:convert'; + import 'package:deep_pick/deep_pick.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:http/http.dart'; +import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/study/study.dart'; import 'package:lichess_mobile/src/model/study/study_filter.dart'; import 'package:lichess_mobile/src/network/http.dart'; @@ -53,4 +56,31 @@ class StudyRepository { }, ); } + + Future<(Study study, String pgn)> getStudy({ + required StudyId id, + StudyChapterId? chapterId, + }) async { + final study = await client.readJson( + Uri( + path: (chapterId != null) ? '/study/$id/$chapterId' : '/study/$id', + queryParameters: { + 'chapters': '1', + }, + ), + headers: {'Accept': 'application/json'}, + mapper: (Map json) { + return Study.fromJson( + pick(json, 'study').asMapOrThrow(), + ); + }, + ); + + final pgnBytes = await client.readBytes( + Uri(path: '/api/study/$id/${chapterId ?? study.chapter.id}.pgn'), + headers: {'Accept': 'application/x-chess-pgn'}, + ); + + return (study, utf8.decode(pgnBytes)); + } }