Skip to content

Commit 1f60dd9

Browse files
committed
feat: full list editor
1 parent 9d3ec41 commit 1f60dd9

File tree

6 files changed

+132
-68
lines changed

6 files changed

+132
-68
lines changed

lib/Api/Anilist/AnilistMutations.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:dartotsu/Api/Anilist/Data/fuzzyData.dart';
12
import 'package:dartotsu/DataClass/Media.dart';
23
import 'package:dartotsu/Services/Api/Mutations.dart';
34
import 'package:flutter/cupertino.dart';

lib/Api/Anilist/AnilistQueries.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:convert';
22
import 'dart:math';
33

44
import 'package:dartotsu/Api/Anilist/Anilist.dart';
5+
import 'package:dartotsu/Api/Anilist/Data/fuzzyData.dart';
56
import 'package:dartotsu/Functions/Function.dart';
67
import 'package:flutter/foundation.dart';
78
import 'package:flutter_qjs/quickjs/ffi.dart';

lib/Api/Anilist/AnilistService.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:get/get.dart';
1111

1212
import '../../Services/BaseServiceData.dart';
1313
import '../../Services/MediaService.dart';
14+
import '../../Widgets/CustomBottomDialog.dart';
1415
import 'Anilist.dart';
1516
import 'ListEditor.dart' as l;
1617
import 'Screen/AnilistHomeScreen.dart';
@@ -51,11 +52,11 @@ class AnilistService extends MediaService {
5152

5253
@override
5354
void compactListEditor(context, media) =>
54-
l.listEditor(context, media, isCompact: true);
55+
showCustomBottomDialog(context, l.ListEditorDialog(media: media));
5556

5657
@override
57-
void listEditor(context, media) =>
58-
l.listEditor(context, media, isCompact: false);
58+
void listEditor(context, media) => showCustomBottomDialog(
59+
context, l.ListEditorDialog(media: media, isCompact: false));
5960
}
6061

6162
class AnilistLoginScreen extends BaseLoginScreen {

lib/Api/Anilist/ListEditor.dart

Lines changed: 110 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
3232
late TextEditingController scoreController;
3333
late bool isPrivate;
3434
late String suffixText;
35+
Map<String, bool>? customListName;
3536
TextEditingController? noteController;
37+
TextEditingController? repeatController;
3638
FuzzyDate? startedAt;
3739
FuzzyDate? completedAt;
3840

@@ -49,8 +51,11 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
4951
: "??");
5052
if (!widget.isCompact) {
5153
noteController = TextEditingController(text: widget.media.notes ?? "");
54+
repeatController =
55+
TextEditingController(text: widget.media.userRepeat.toString());
5256
startedAt = media.userStartedAt;
5357
completedAt = media.userCompletedAt;
58+
customListName = Map<String, bool>.from(media.inCustomListsOf ?? {});
5459
}
5560
isPrivate = media.isListPrivate;
5661
suffixText =
@@ -62,6 +67,8 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
6267
super.dispose();
6368
progressController.dispose();
6469
scoreController.dispose();
70+
noteController?.dispose();
71+
repeatController?.dispose();
6572
}
6673

6774
@override
@@ -81,40 +88,38 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
8188
return CustomBottomDialog(
8289
title: "List Editor",
8390
viewList: [
84-
Column(
85-
children: [
86-
_buildStatusDropdown(fieldPadding),
87-
Padding(
88-
padding: fieldPadding,
89-
child: _buildProgressField(labelStyle, suffixStyle),
90-
),
91-
Padding(
92-
padding: fieldPadding,
93-
child: _buildScoreField(labelStyle, suffixStyle),
94-
),
95-
if (!widget.isCompact)
96-
Padding(
97-
padding: fieldPadding,
98-
child: _buildDatePickerRow(suffixStyle),
99-
),
100-
Padding(
101-
padding: const EdgeInsets.symmetric(horizontal: 8.0),
102-
child: _buildPrivateSwitch(),
103-
),
104-
if (!widget.isCompact)
105-
Expandable(
106-
backgroundColor: theme.surface,
107-
boxShadow: [],
108-
arrowWidget:
109-
const Icon(Icons.keyboard_arrow_up_rounded, size: 25.0),
110-
firstChild: const Text('Other', style: suffixStyle),
111-
secondChild: _buildOtherWidget(
112-
labelStyle,
113-
suffixStyle,
114-
fieldPadding,
91+
Padding(
92+
padding: fieldPadding,
93+
child: Column(
94+
children: [
95+
_buildStatusDropdown(),
96+
const SizedBox(height: 16),
97+
_buildProgressField(labelStyle, suffixStyle),
98+
const SizedBox(height: 8),
99+
_buildScoreField(labelStyle, suffixStyle),
100+
const SizedBox(height: 8),
101+
if (!widget.isCompact) ...[
102+
_buildDatePickerRow(suffixStyle),
103+
const SizedBox(height: 8),
104+
],
105+
_buildPrivateSwitch(),
106+
const SizedBox(height: 8),
107+
if (!widget.isCompact) ...[
108+
Expandable(
109+
backgroundColor: theme.surface,
110+
boxShadow: [],
111+
arrowWidget:
112+
const Icon(Icons.keyboard_arrow_up_rounded, size: 25.0),
113+
firstChild: const Text('Other', style: suffixStyle),
114+
secondChild: _buildOtherWidget(
115+
labelStyle,
116+
suffixStyle,
117+
),
115118
),
116-
),
117-
],
119+
const SizedBox(height: 8),
120+
]
121+
],
122+
),
118123
),
119124
],
120125
positiveText: 'Save',
@@ -123,9 +128,9 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
123128
);
124129
}
125130

126-
Widget _buildStatusDropdown(EdgeInsetsGeometry padding) {
131+
Widget _buildStatusDropdown() {
127132
return buildDropdownMenu(
128-
padding: padding,
133+
padding: const EdgeInsets.all(0),
129134
borderRadius: 16,
130135
prefixIcon: Icons.playlist_play_rounded,
131136
options: Anilist.status,
@@ -143,33 +148,76 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
143148
Widget _buildOtherWidget(
144149
TextStyle labelStyle,
145150
TextStyle suffixStyle,
146-
EdgeInsetsGeometry padding,
147151
) {
148152
return Column(
153+
crossAxisAlignment: CrossAxisAlignment.start,
149154
children: [
150-
Padding(
151-
padding: padding,
152-
child: TextField(
153-
controller: noteController,
154-
maxLines: null,
155-
keyboardType: TextInputType.multiline,
156-
style: labelStyle,
157-
decoration: InputDecoration(
158-
labelText: "Note",
159-
labelStyle: labelStyle,
160-
prefixIcon: const Icon(Icons.edit_note_rounded),
161-
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
162-
border: OutlineInputBorder(
163-
borderRadius: BorderRadius.circular(16),
164-
borderSide: const BorderSide(color: Colors.transparent),
165-
),
155+
const SizedBox(height: 8),
156+
TextField(
157+
controller: repeatController,
158+
keyboardType: const TextInputType.numberWithOptions(decimal: false),
159+
style: labelStyle,
160+
inputFormatters: [
161+
FilteringTextInputFormatter.allow(RegExp(r'^[0-9]*$')),
162+
],
163+
decoration: InputDecoration(
164+
labelText: "Total Repeats",
165+
labelStyle: labelStyle,
166+
suffixStyle: suffixStyle,
167+
prefixIcon: const Icon(Icons.redo_rounded),
168+
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
169+
border: OutlineInputBorder(
170+
borderRadius: BorderRadius.circular(16),
171+
borderSide: const BorderSide(color: Colors.transparent),
172+
),
173+
),
174+
),
175+
const SizedBox(height: 8),
176+
TextField(
177+
controller: noteController,
178+
maxLines: null,
179+
keyboardType: TextInputType.multiline,
180+
style: labelStyle,
181+
decoration: InputDecoration(
182+
labelText: "Note",
183+
labelStyle: labelStyle,
184+
prefixIcon: const Icon(Icons.edit_note_rounded),
185+
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
186+
border: OutlineInputBorder(
187+
borderRadius: BorderRadius.circular(16),
188+
borderSide: const BorderSide(color: Colors.transparent),
166189
),
167190
),
168191
),
192+
const SizedBox(height: 16),
193+
..._buildCustomListWidgets(suffixStyle),
169194
],
170195
);
171196
}
172197

198+
List<Widget> _buildCustomListWidgets(TextStyle suffixStyle) {
199+
200+
if (customListName == null || customListName!.isEmpty) {
201+
return [Text("No custom lists available", style: suffixStyle)];
202+
}
203+
204+
return [
205+
Text("Custom Lists", style: suffixStyle),
206+
const SizedBox(height: 16),
207+
...customListName!.entries.map(
208+
(entry) => SwitchListTile(
209+
title: Text(entry.key),
210+
value: entry.value,
211+
onChanged: (value) {
212+
setState(() {
213+
customListName![entry.key] = value;
214+
});
215+
},
216+
),
217+
)
218+
];
219+
}
220+
173221
Widget _buildProgressField(TextStyle labelStyle, TextStyle suffixStyle) {
174222
return Row(
175223
children: [
@@ -276,7 +324,7 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
276324
context: context,
277325
initialDate: initialDate,
278326
firstDate: DateTime(1900),
279-
lastDate: DateTime.now().add(const Duration(days: 365 * 5)),
327+
lastDate: DateTime.now(),
280328
);
281329
if (picked != null) onDatePicked(picked);
282330
},
@@ -350,14 +398,21 @@ class _ListEditorDialogState extends State<ListEditorDialog> {
350398
.clamp(0, 100)
351399
..isListPrivate = isPrivate;
352400

401+
List<String>? list;
353402
if (!widget.isCompact) {
354403
widget.media
355404
..notes = noteController?.text
356405
..userStartedAt = startedAt
357-
..userCompletedAt = completedAt;
406+
..userCompletedAt = completedAt
407+
..userRepeat = int.tryParse(repeatController?.text ?? "1") ?? 1;
408+
widget.media.inCustomListsOf = customListName;
409+
list = customListName?.entries
410+
.where((entry) => entry.value)
411+
.map((entry) => entry.key)
412+
.toList();
358413
}
359414

360-
Anilist.mutations?.editList(widget.media);
415+
Anilist.mutations?.editList(widget.media,customList: list);
361416
Get.back();
362417
Refresh.activity[RefreshId.Anilist.homePage]?.value = true;
363418
}

lib/DataClass/Media.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ class Media {
6666
int? userScore = 0;
6767
int userRepeat = 0;
6868
int? userUpdatedAt;
69-
dynamic userStartedAt = FuzzyDate();
70-
dynamic userCompletedAt = FuzzyDate();
69+
FuzzyDate? userStartedAt = FuzzyDate();
70+
FuzzyDate? userCompletedAt = FuzzyDate();
7171
Map<String, bool>? inCustomListsOf;
7272
int? userFavOrder;
7373

@@ -136,8 +136,8 @@ class Media {
136136
this.userScore = 0,
137137
this.userRepeat = 0,
138138
this.userUpdatedAt,
139-
this.userStartedAt = 0,
140-
this.userCompletedAt = 0,
139+
this.userStartedAt,
140+
this.userCompletedAt,
141141
this.inCustomListsOf,
142142
this.userFavOrder,
143143
this.status,

lib/Screens/Detail/Tabs/Watch/BaseParser.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import 'package:async/async.dart';
2-
import 'package:dartotsu/Preferences/IsarDataClasses/MediaSettings/MediaSettings.dart';
32
import 'package:dartotsu/Theme/LanguageSwitcher.dart';
43
import 'package:flutter/cupertino.dart';
54
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
@@ -12,6 +11,7 @@ import '../../../../Api/Sources/Search/search.dart';
1211
import '../../../../DataClass/Media.dart';
1312
import '../../../../Functions/GetExtensions.dart';
1413
import '../../../../Preferences/IsarDataClasses/ShowResponse/ShowResponse.dart';
14+
import '../../../../Preferences/PrefManager.dart';
1515
import '../../../../Widgets/CustomBottomDialog.dart';
1616
import '../../../Settings/language.dart';
1717
import 'Widgets/WrongTitle.dart';
@@ -82,7 +82,8 @@ abstract class BaseParser extends GetxController {
8282
Future<void> _performSearch(Source source, Media mediaData,
8383
Function(MManga? response)? onFinish) async {
8484
selectedMedia.value = null;
85-
var saved = mediaData.settings.showResponse;
85+
status.value = "Searching...";
86+
var saved = _loadShowResponse(source, mediaData);
8687
if (saved != null) {
8788
var response = MManga(
8889
name: saved.name,
@@ -199,16 +200,21 @@ abstract class BaseParser extends GetxController {
199200
return englishRegex.hasMatch(name);
200201
}
201202

203+
ShowResponse? _loadShowResponse(Source source, Media mediaData) {
204+
return loadCustomData<ShowResponse?>(
205+
"${source.name}_${mediaData.id}_source");
206+
}
207+
202208
_saveShowResponse(Media mediaData, MManga response, Source source,
203209
{bool selected = false}) {
204-
status.value = selected
205-
? "${getString.selected} : ${response.name}"
206-
: "${getString.found} : ${response.name}";
210+
status.value =
211+
selected ? "${getString.selected} : ${response.name}" : "${getString.found} : ${response.name}";
207212
var show = ShowResponse(
208213
name: response.name!,
209214
link: response.link!,
210215
coverUrl: response.imageUrl!);
211-
MediaSettings.saveMediaSettings(mediaData..settings.showResponse = show);
216+
saveCustomData<ShowResponse>(
217+
"${source.name}_${mediaData.id}_source", show);
212218
}
213219

214220
Future<void> wrongTitle(

0 commit comments

Comments
 (0)