forked from lichess-org/mobile
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstudy.dart
More file actions
185 lines (154 loc) · 5.96 KB
/
study.dart
File metadata and controls
185 lines (154 loc) · 5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import 'package:collection/collection.dart';
import 'package:dartchess/dartchess.dart';
import 'package:deep_pick/deep_pick.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
class Study with _$Study {
const Study._();
const factory Study({
required StudyId id,
required String name,
required bool liked,
required int likes,
required UserId? ownerId,
required StudyFeatures features,
required IList<String> topics,
required IList<StudyChapterMeta> chapters,
required StudyChapter chapter,
/// Hints to display in "gamebook"/"interactive" mode
/// Index corresponds to the current ply.
required IList<String?> hints,
/// Comment to display when deviating from the mainline in "gamebook" mode
/// (i.e. when making a wrong move).
/// Index corresponds to the current ply.
required IList<String?> deviationComments,
}) = _Study;
/// Returns the indexed name of a chapter given its [chapterId].
///
/// The indexed name is a string that combines the chapter's index (1-based)
/// and its name, formatted as "index. name".
///
/// Throws a [RangeError] if the chapter with the given [chapterId] is not found.
///
/// Example:
/// ```dart
/// final chapterName = study.getChapterIndexedName(chapterId);
/// print(chapterName); // Output: "1. Chapter Name"
/// ```
///
/// - Parameter chapterId: The ID of the chapter to find.
/// - Returns: A string representing the indexed name of the chapter.
String getChapterIndexedName(StudyChapterId chapterId) {
final index = chapters.indexWhere((c) => c.id == chapterId);
return '${index + 1}. ${chapters[index].name}';
}
StudyChapterMeta get currentChapterMeta => chapters.firstWhere((c) => c.id == chapter.id);
factory Study.fromServerJson(Map<String, Object?> json) {
return _studyFromPick(pick(json).required());
}
}
Study _studyFromPick(RequiredPick pick) {
final treeParts = pick('analysis', 'treeParts').asListOrThrow((part) => part);
final hints = <String?>[];
final deviationComments = <String?>[];
for (final part in treeParts) {
hints.add(part('gamebook', 'hint').asStringOrNull());
deviationComments.add(part('gamebook', 'deviation').asStringOrNull());
}
final study = pick('study');
return Study(
id: study('id').asStudyIdOrThrow(),
name: study('name').asStringOrThrow(),
liked: study('liked').asBoolOrThrow(),
likes: study('likes').asIntOrThrow(),
ownerId: study('ownerId').asUserIdOrNull(),
features: (
cloneable: study('features', 'cloneable').asBoolOrFalse(),
chat: study('features', 'chat').asBoolOrFalse(),
sticky: study('features', 'sticky').asBoolOrFalse(),
),
topics: study('topics').asListOrThrow((pick) => pick.asStringOrThrow()).lock,
chapters:
study(
'chapters',
).asListOrThrow((pick) => StudyChapterMeta.fromJson(pick.asMapOrThrow())).lock,
chapter: StudyChapter.fromJson(study('chapter').asMapOrThrow()),
hints: hints.lock,
deviationComments: deviationComments.lock,
);
}
typedef StudyFeatures = ({bool cloneable, bool chat, bool sticky});
@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,
@JsonKey(fromJson: studyChapterFeaturesFromJson) required StudyChapterFeatures features,
}) = _StudyChapter;
factory StudyChapter.fromJson(Map<String, Object?> json) => _$StudyChapterFromJson(json);
}
typedef StudyChapterFeatures = ({bool computer, bool explorer});
StudyChapterFeatures studyChapterFeaturesFromJson(Map<String, Object?> json) {
return (
computer: json['computer'] as bool? ?? false,
explorer: json['explorer'] as bool? ?? false,
);
}
@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<String, Object?> json) =>
_$StudyChapterSetupFromJson(json);
}
Variant _variantFromJson(Map<String, Object?> 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<String, Object?> json) => _$StudyChapterMetaFromJson(json);
}
@Freezed(fromJson: true)
class StudyPageData with _$StudyPageData {
const StudyPageData._();
const factory StudyPageData({
required StudyId id,
required String name,
required bool liked,
required int likes,
@JsonKey(fromJson: DateTime.fromMillisecondsSinceEpoch) required DateTime updatedAt,
required LightUser? owner,
required IList<String> topics,
required IList<StudyMember> members,
required IList<String> chapters,
required String? flair,
}) = _StudyPageData;
factory StudyPageData.fromJson(Map<String, Object?> json) => _$StudyPageDataFromJson(json);
}
@Freezed(fromJson: true)
class StudyMember with _$StudyMember {
const StudyMember._();
const factory StudyMember({required LightUser user, required String role}) = _StudyMember;
factory StudyMember.fromJson(Map<String, Object?> json) => _$StudyMemberFromJson(json);
}