mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-21 16:01:58 +00:00
added sequels
This commit is contained in:
parent
b57015b682
commit
5b806f6dd6
20 changed files with 395 additions and 88 deletions
|
|
@ -537,6 +537,7 @@
|
|||
"clear_library_desc": "Choose to clear all manga, anime and/or novel entries",
|
||||
"clear_library_input": "Type 'manga', 'anime' and/or 'novel' (separated by a comma) to remove all related entries",
|
||||
"watch_order": "Watch order",
|
||||
"sequels": "Sequels",
|
||||
"recommendations": "Recommendations",
|
||||
"recommendations_similarity": "Similarity:"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3297,6 +3297,12 @@ abstract class AppLocalizations {
|
|||
/// **'Watch order'**
|
||||
String get watch_order;
|
||||
|
||||
/// No description provided for @sequels.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sequels'**
|
||||
String get sequels;
|
||||
|
||||
/// No description provided for @recommendations_similarity.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
|
|
@ -1706,6 +1706,9 @@ class AppLocalizationsAr extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1708,6 +1708,9 @@ class AppLocalizationsAs extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1719,6 +1719,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1707,6 +1707,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1724,6 +1724,9 @@ class AppLocalizationsEs extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1725,6 +1725,9 @@ class AppLocalizationsFr extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1709,6 +1709,9 @@ class AppLocalizationsHi extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1713,6 +1713,9 @@ class AppLocalizationsId extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1722,6 +1722,9 @@ class AppLocalizationsIt extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1721,6 +1721,9 @@ class AppLocalizationsPt extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1723,6 +1723,9 @@ class AppLocalizationsRu extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1707,6 +1707,9 @@ class AppLocalizationsTh extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1713,6 +1713,9 @@ class AppLocalizationsTr extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1678,6 +1678,9 @@ class AppLocalizationsZh extends AppLocalizations {
|
|||
@override
|
||||
String get watch_order => 'Watch order';
|
||||
|
||||
@override
|
||||
String get sequels => 'Sequels';
|
||||
|
||||
@override
|
||||
String get recommendations_similarity => 'Similarity:';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provi
|
|||
import 'package:mangayomi/modules/more/providers/algorithm_weights_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/pure_black_dark_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/track/widgets/track_listile.dart';
|
||||
import 'package:mangayomi/modules/tracker_library/tracker_library_screen.dart';
|
||||
import 'package:mangayomi/modules/widgets/bottom_select_bar.dart';
|
||||
import 'package:mangayomi/modules/widgets/category_selection_dialog.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart';
|
||||
|
|
@ -1660,7 +1661,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
onPressed: () {
|
||||
context.push(
|
||||
"/watchOrder",
|
||||
extra: widget.manga!.name,
|
||||
extra: (widget.manga!.name, null),
|
||||
);
|
||||
},
|
||||
label: Text(l10n.watch_order),
|
||||
|
|
@ -1668,6 +1669,60 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
),
|
||||
),
|
||||
),
|
||||
if (widget.manga!.itemType == ItemType.anime)
|
||||
StreamBuilder(
|
||||
stream: isar.tracks
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.mangaIdEqualTo(widget.manga!.id!)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
List<Track>? trackRes = snapshot.hasData
|
||||
? snapshot.data
|
||||
: [];
|
||||
final isNotSupported =
|
||||
trackRes?.firstOrNull?.syncId !=
|
||||
TrackerProviders.myAnimeList.syncId &&
|
||||
trackRes?.firstOrNull?.syncId !=
|
||||
TrackerProviders.anilist.syncId;
|
||||
if ((trackRes?.isEmpty ?? true) || (isNotSupported)) {
|
||||
return Container();
|
||||
}
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 15),
|
||||
SizedBox(
|
||||
width: context.width(1),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: OutlinedButton.icon(
|
||||
style: ButtonStyle(
|
||||
shape: WidgetStatePropertyAll(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
30.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context.push(
|
||||
"/watchOrder",
|
||||
extra: (
|
||||
widget.manga!.name,
|
||||
trackRes?.firstOrNull,
|
||||
),
|
||||
);
|
||||
},
|
||||
label: Text(l10n.sequels),
|
||||
icon: Icon(Icons.arrow_right_alt_outlined),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
if (!context.isTablet)
|
||||
Column(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/track.dart';
|
||||
import 'package:mangayomi/models/track_preference.dart';
|
||||
import 'package:mangayomi/modules/tracker_library/tracker_library_screen.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_extended_image_provider.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/services/fetch_watch_order.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:marquee/marquee.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:photo_view/photo_view_gallery.dart';
|
||||
|
|
@ -13,8 +19,9 @@ import 'package:super_sliver_list/super_sliver_list.dart';
|
|||
|
||||
class WatchOrderScreen extends StatefulWidget {
|
||||
final String name;
|
||||
final Track? track;
|
||||
|
||||
const WatchOrderScreen({super.key, required this.name});
|
||||
const WatchOrderScreen({super.key, required this.name, required this.track});
|
||||
|
||||
@override
|
||||
State<WatchOrderScreen> createState() => _WatchOrderScreenState();
|
||||
|
|
@ -23,9 +30,12 @@ class WatchOrderScreen extends StatefulWidget {
|
|||
class _WatchOrderScreenState extends State<WatchOrderScreen> {
|
||||
String _errorMessage = "";
|
||||
bool _isLoading = true;
|
||||
List<SequelItem>? sequels;
|
||||
List<WatchOrderSearch>? dataSearch;
|
||||
List<WatchOrderItem>? data;
|
||||
|
||||
bool get isSequels => widget.track != null;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -35,7 +45,23 @@ class _WatchOrderScreenState extends State<WatchOrderScreen> {
|
|||
Future<void> _init() async {
|
||||
try {
|
||||
_errorMessage = "";
|
||||
dataSearch = await searchWatchOrder(widget.name);
|
||||
if (isSequels) {
|
||||
final mediaId = widget.track!.mediaId!.toString();
|
||||
final mal = await isar.trackPreferences
|
||||
.filter()
|
||||
.syncIdEqualTo(TrackerProviders.myAnimeList.syncId)
|
||||
.findFirst();
|
||||
final anilist = await isar.trackPreferences
|
||||
.filter()
|
||||
.syncIdEqualTo(TrackerProviders.anilist.syncId)
|
||||
.findFirst();
|
||||
final data = await fetchSequels(mal?.username, anilist?.username);
|
||||
sequels = data
|
||||
.where((e) => e.reason.any((r) => r.id == mediaId))
|
||||
.toList();
|
||||
} else {
|
||||
dataSearch = await searchWatchOrder(widget.name);
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
|
|
@ -55,7 +81,7 @@ class _WatchOrderScreenState extends State<WatchOrderScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(l10n.watch_order)),
|
||||
appBar: AppBar(title: Text(isSequels ? l10n.sequels : l10n.watch_order)),
|
||||
body: Padding(
|
||||
padding: EdgeInsetsGeometry.all(5),
|
||||
child: _isLoading
|
||||
|
|
@ -65,85 +91,131 @@ class _WatchOrderScreenState extends State<WatchOrderScreen> {
|
|||
if (_errorMessage.isNotEmpty) {
|
||||
return Center(child: Text(_errorMessage));
|
||||
}
|
||||
final isSearch = dataSearch != null && dataSearch!.isNotEmpty;
|
||||
final isWatchOrder = data != null && data!.isNotEmpty;
|
||||
if (isSearch || isWatchOrder) {
|
||||
return SuperListView.builder(
|
||||
extentPrecalculationPolicy: SuperPrecalculationPolicy(),
|
||||
itemCount: data?.length ?? dataSearch!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final search = !isWatchOrder && isSearch
|
||||
? dataSearch![index]
|
||||
: null;
|
||||
final watchOrder = isWatchOrder ? data![index] : null;
|
||||
return ListTile(
|
||||
onTap: () async {
|
||||
if (isWatchOrder) {
|
||||
context.push(
|
||||
'/globalSearch',
|
||||
extra: (
|
||||
watchOrder!.nameEnglish ?? watchOrder.name,
|
||||
ItemType.anime,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_errorMessage = "";
|
||||
});
|
||||
data = await fetchWatchOrder(search!.id);
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
title: Row(
|
||||
children: [
|
||||
_thumbnailPreview(
|
||||
context,
|
||||
watchOrder?.image ?? search!.image,
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTitle(
|
||||
watchOrder?.name ?? search!.name,
|
||||
context,
|
||||
),
|
||||
if (watchOrder?.nameEnglish != null &&
|
||||
watchOrder?.nameEnglish !=
|
||||
watchOrder?.text)
|
||||
Text(
|
||||
watchOrder!.nameEnglish!,
|
||||
style: const TextStyle(fontSize: 11),
|
||||
overflow: TextOverflow.clip,
|
||||
),
|
||||
Text(
|
||||
watchOrder?.text ??
|
||||
"${search!.type} - ${search.year}",
|
||||
style: const TextStyle(fontSize: 11),
|
||||
overflow: TextOverflow.clip,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return Center(child: Text(l10n.no_result));
|
||||
return isSequels ? _buildSequels() : _buildWatchOrder();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSequels() {
|
||||
if (sequels != null && sequels!.isNotEmpty) {
|
||||
return SuperListView.builder(
|
||||
extentPrecalculationPolicy: SuperPrecalculationPolicy(),
|
||||
itemCount: sequels!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final sequel = sequels![index];
|
||||
return StreamBuilder(
|
||||
stream: isar.tracks
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.mediaIdEqualTo(int.tryParse(sequel.id))
|
||||
.or()
|
||||
.mediaIdEqualTo(int.tryParse(sequel.anilistId ?? ""))
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
final hasData = snapshot.hasData && snapshot.data!.isNotEmpty;
|
||||
return ListTile(
|
||||
onTap: () async {
|
||||
context.push(
|
||||
'/globalSearch',
|
||||
extra: (sequel.title, ItemType.anime),
|
||||
);
|
||||
},
|
||||
title: Row(
|
||||
children: [
|
||||
_thumbnailPreview(context, sequel.image, hasData: hasData),
|
||||
const SizedBox(width: 15),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTitle(sequel.title, context),
|
||||
Text(
|
||||
"${sequel.period} | ${sequel.type} | ${sequel.episodes} episodes | ★${sequel.score} (${sequel.scoreUsers})",
|
||||
style: const TextStyle(fontSize: 11),
|
||||
overflow: TextOverflow.clip,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return Center(child: Text(context.l10n.no_result));
|
||||
}
|
||||
|
||||
Widget _buildWatchOrder() {
|
||||
final isSearch = dataSearch != null && dataSearch!.isNotEmpty;
|
||||
final isWatchOrder = data != null && data!.isNotEmpty;
|
||||
if (isSearch || isWatchOrder) {
|
||||
return SuperListView.builder(
|
||||
extentPrecalculationPolicy: SuperPrecalculationPolicy(),
|
||||
itemCount: data?.length ?? dataSearch!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final search = !isWatchOrder && isSearch ? dataSearch![index] : null;
|
||||
final watchOrder = isWatchOrder ? data![index] : null;
|
||||
return ListTile(
|
||||
onTap: () async {
|
||||
if (isWatchOrder) {
|
||||
context.push(
|
||||
'/globalSearch',
|
||||
extra: (
|
||||
watchOrder!.nameEnglish ?? watchOrder.name,
|
||||
ItemType.anime,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_errorMessage = "";
|
||||
});
|
||||
data = await fetchWatchOrder(search!.id);
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
title: Row(
|
||||
children: [
|
||||
_thumbnailPreview(context, watchOrder?.image ?? search!.image),
|
||||
const SizedBox(width: 15),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTitle(watchOrder?.name ?? search!.name, context),
|
||||
if (watchOrder?.nameEnglish != null &&
|
||||
watchOrder?.nameEnglish != watchOrder?.text)
|
||||
Text(
|
||||
watchOrder!.nameEnglish!,
|
||||
style: const TextStyle(fontSize: 11),
|
||||
overflow: TextOverflow.clip,
|
||||
),
|
||||
Text(
|
||||
watchOrder?.text ?? "${search!.type} - ${search.year}",
|
||||
style: const TextStyle(fontSize: 11),
|
||||
overflow: TextOverflow.clip,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return Center(child: Text(context.l10n.no_result));
|
||||
}
|
||||
|
||||
Widget _buildTitle(String text, BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
|
|
@ -183,7 +255,11 @@ class _WatchOrderScreenState extends State<WatchOrderScreen> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _thumbnailPreview(BuildContext context, String? imageUrl) {
|
||||
Widget _thumbnailPreview(
|
||||
BuildContext context,
|
||||
String? imageUrl, {
|
||||
bool hasData = false,
|
||||
}) {
|
||||
final imageProvider = CustomExtendedNetworkImageProvider(
|
||||
toImgUrl(imageUrl ?? ""),
|
||||
);
|
||||
|
|
@ -193,15 +269,39 @@ class _WatchOrderScreenState extends State<WatchOrderScreen> {
|
|||
onTap: () {
|
||||
_openImage(context, imageProvider);
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 100,
|
||||
height: 150,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(5)),
|
||||
image: DecorationImage(image: imageProvider, fit: BoxFit.cover),
|
||||
child: Stack(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 100,
|
||||
height: 150,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(5)),
|
||||
image: DecorationImage(
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 100,
|
||||
height: 150,
|
||||
color: hasData ? Colors.black.withValues(alpha: 0.7) : null,
|
||||
),
|
||||
if (hasData)
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Icon(
|
||||
Icons.collections_bookmark,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/track.dart';
|
||||
import 'package:mangayomi/models/track_preference.dart';
|
||||
import 'package:mangayomi/models/track_search.dart';
|
||||
import 'package:mangayomi/modules/anime/anime_player_view.dart';
|
||||
|
|
@ -257,9 +258,9 @@ class RouterNotifier extends ChangeNotifier {
|
|||
algorithmWeights: data.$3,
|
||||
),
|
||||
),
|
||||
_genericRoute<String>(
|
||||
_genericRoute<(String, Track?)>(
|
||||
name: "watchOrder",
|
||||
builder: (data) => WatchOrderScreen(name: data),
|
||||
builder: (data) => WatchOrderScreen(name: data.$1, track: data.$2),
|
||||
),
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,41 @@ import 'package:html/dom.dart';
|
|||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:mangayomi/utils/extensions/dom_extensions.dart';
|
||||
|
||||
const _sequelData =
|
||||
"&types%5B%5D=1&types%5B%5D=3&types%5B%5D=2&types%5B%5D=4&types%5B%5D=9&score=0&date_from=false&date_to=false&include_ptw=1&exclude_h=1&exclude_planned=1&exclude_dropped=0&exclude_not_aired=0&exclude_short=1&exclude_short_value=3";
|
||||
|
||||
Future<List<SequelItem>> fetchSequels(
|
||||
String? malUsername,
|
||||
String? anilistUsername,
|
||||
) async {
|
||||
if (malUsername == null && anilistUsername == null) {
|
||||
return [];
|
||||
}
|
||||
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
|
||||
try {
|
||||
final url = Uri.parse("https://chiaki.site/?/tools/sequel_locator_fetch");
|
||||
final res = await http.post(
|
||||
url,
|
||||
headers: {
|
||||
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"priority": "u=1, i",
|
||||
"Referer": "https://chiaki.site/?/tools/watch_order",
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
},
|
||||
body:
|
||||
"user=${malUsername ?? anilistUsername}&list_source=${malUsername != null ? "mal" : "anilist"}$_sequelData",
|
||||
);
|
||||
final data = jsonDecode(res.body) as Map<String, dynamic>?;
|
||||
return (data?["data"] as List?)
|
||||
?.map((e) => SequelItem.fromJson(e))
|
||||
.toList() ??
|
||||
[];
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<WatchOrderSearch>> searchWatchOrder(String name) async {
|
||||
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
|
||||
try {
|
||||
|
|
@ -71,6 +106,73 @@ Future<List<WatchOrderItem>> fetchWatchOrder(String id) async {
|
|||
}
|
||||
}
|
||||
|
||||
class SequelItem {
|
||||
final String id;
|
||||
final String? anilistId;
|
||||
final String image;
|
||||
final String episodes;
|
||||
final String title;
|
||||
final String group;
|
||||
final String groupId;
|
||||
final String period;
|
||||
final String score;
|
||||
final String scoreUsers;
|
||||
final String type;
|
||||
final List<SequelReason> reason;
|
||||
|
||||
SequelItem({
|
||||
required this.id,
|
||||
required this.anilistId,
|
||||
required this.image,
|
||||
required this.episodes,
|
||||
required this.title,
|
||||
required this.group,
|
||||
required this.groupId,
|
||||
required this.period,
|
||||
required this.score,
|
||||
required this.scoreUsers,
|
||||
required this.type,
|
||||
required this.reason,
|
||||
});
|
||||
|
||||
factory SequelItem.fromJson(Map<String, dynamic> json) {
|
||||
return SequelItem(
|
||||
id: json["id"],
|
||||
anilistId: json["anilist_id"],
|
||||
image: "https://chiaki.site/${json["image_url"]}",
|
||||
episodes: json["episodes"],
|
||||
title: json["title"],
|
||||
group: json["group"],
|
||||
groupId: json["group_id"],
|
||||
period: json["period"],
|
||||
score: json["score"],
|
||||
scoreUsers: json["score_users"],
|
||||
type: json["type"],
|
||||
reason:
|
||||
(json["reason"] as List?)
|
||||
?.map((e) => SequelReason.fromJson(e))
|
||||
.toList() ??
|
||||
[],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SequelReason {
|
||||
final String id;
|
||||
final String image;
|
||||
final String title;
|
||||
|
||||
SequelReason({required this.id, required this.image, required this.title});
|
||||
|
||||
factory SequelReason.fromJson(Map<String, dynamic> json) {
|
||||
return SequelReason(
|
||||
id: json["id"],
|
||||
image: "https://chiaki.site/${json["image_url"]}",
|
||||
title: json["title"],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WatchOrderSearch {
|
||||
final String id;
|
||||
final String image;
|
||||
|
|
|
|||
Loading…
Reference in a new issue