mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-20 23:22:07 +00:00
+
This commit is contained in:
parent
4c3b6bc430
commit
e994d3230a
11 changed files with 235 additions and 356 deletions
|
|
@ -5,6 +5,7 @@ import 'package:app_links/app_links.dart';
|
|||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
|
@ -117,6 +118,7 @@ class _MyAppState extends ConsumerState<MyApp> {
|
|||
routerDelegate: router.routerDelegate,
|
||||
routeInformationProvider: router.routeInformationProvider,
|
||||
title: 'MangaYomi',
|
||||
scrollBehavior: AllowDesktopScrollBehavior(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -230,3 +232,11 @@ class _MyAppState extends ConsumerState<MyApp> {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class AllowDesktopScrollBehavior extends MaterialScrollBehavior {
|
||||
@override
|
||||
Set<PointerDeviceKind> get dragDevices => {
|
||||
PointerDeviceKind.touch,
|
||||
PointerDeviceKind.mouse,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -325,6 +325,42 @@ class _MainScreenState extends ConsumerState<MainScreen> {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (dest.contains("/trackerLibrary/anilist")) {
|
||||
destinations[dest.indexOf(
|
||||
"/trackerLibrary/anilist",
|
||||
)] = NavigationRailDestination(
|
||||
selectedIcon: const Icon(Icons.account_tree),
|
||||
icon: const Icon(Icons.account_tree_outlined),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text("AL"),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (dest.contains("/trackerLibrary/kitsu")) {
|
||||
destinations[dest.indexOf(
|
||||
"/trackerLibrary/kitsu",
|
||||
)] = NavigationRailDestination(
|
||||
selectedIcon: const Icon(Icons.account_tree),
|
||||
icon: const Icon(Icons.account_tree_outlined),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text("Kitsu"),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (dest.contains("/trackerLibrary/mal")) {
|
||||
destinations[dest.indexOf(
|
||||
"/trackerLibrary/mal",
|
||||
)] = NavigationRailDestination(
|
||||
selectedIcon: const Icon(Icons.account_tree),
|
||||
icon: const Icon(Icons.account_tree_outlined),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(top: 5),
|
||||
child: Text("MAL"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final result = destinations.nonNulls.toList();
|
||||
_desktopDestinationsCache[cacheKey] = result;
|
||||
|
|
@ -408,6 +444,31 @@ class _MainScreenState extends ConsumerState<MainScreen> {
|
|||
label: l10n.more,
|
||||
);
|
||||
}
|
||||
if (dest.contains("/trackerLibrary/anilist")) {
|
||||
destinations[dest.indexOf(
|
||||
"/trackerLibrary/anilist",
|
||||
)] = NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.account_tree),
|
||||
icon: const Icon(Icons.account_tree_outlined),
|
||||
label: "AL",
|
||||
);
|
||||
}
|
||||
if (dest.contains("/trackerLibrary/kitsu")) {
|
||||
destinations[dest.indexOf(
|
||||
"/trackerLibrary/kitsu",
|
||||
)] = NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.account_tree),
|
||||
icon: const Icon(Icons.account_tree_outlined),
|
||||
label: "Kitsu",
|
||||
);
|
||||
}
|
||||
if (dest.contains("/trackerLibrary/mal")) {
|
||||
destinations[dest.indexOf("/trackerLibrary/mal")] = NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.account_tree),
|
||||
icon: const Icon(Icons.account_tree_outlined),
|
||||
label: "MAL",
|
||||
);
|
||||
}
|
||||
|
||||
_mobileDestinationsCache[cacheKey] = destinations;
|
||||
return destinations;
|
||||
|
|
@ -527,6 +588,9 @@ class _TabletLayout extends StatelessWidget {
|
|||
'/updates',
|
||||
'/browse',
|
||||
'/more',
|
||||
'/trackerLibrary/anilist',
|
||||
'/trackerLibrary/kitsu',
|
||||
'/trackerLibrary/mal',
|
||||
};
|
||||
|
||||
return (location == null || validLocations.contains(location)) ? 100 : 0;
|
||||
|
|
@ -594,6 +658,9 @@ class _MobileBottomNavigation extends StatelessWidget {
|
|||
'/updates',
|
||||
'/browse',
|
||||
'/more',
|
||||
'/trackerLibrary/anilist',
|
||||
'/trackerLibrary/kitsu',
|
||||
'/trackerLibrary/mal',
|
||||
};
|
||||
|
||||
return (location == null || validLocations.contains(location)) ? null : 0;
|
||||
|
|
|
|||
|
|
@ -139,15 +139,20 @@ class TrackState extends _$TrackState {
|
|||
return await tracker.search(query, _isManga);
|
||||
}
|
||||
|
||||
Future<List<TrackSearch>?> fetchGeneralData({String rankingType = "airing"}) async {
|
||||
Future<List<TrackSearch>?> fetchGeneralData({
|
||||
String rankingType = "airing",
|
||||
}) async {
|
||||
final syncId = track!.syncId!;
|
||||
final tracker = getNotifier(syncId);
|
||||
return await tracker.fetchGeneralData(_isManga, rankingType);
|
||||
return await tracker.fetchGeneralData(
|
||||
isManga: _isManga,
|
||||
rankingType: rankingType,
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<TrackSearch>?> fetchUserData() async {
|
||||
final syncId = track!.syncId!;
|
||||
final tracker = getNotifier(syncId);
|
||||
return await tracker.fetchUserData(_isManga);
|
||||
return await tracker.fetchUserData(isManga: _isManga);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'track_state_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$trackStateHash() => r'67e97d5b4e253e4289799c5d43bfa96e7f2b5140';
|
||||
String _$trackStateHash() => r'b10c02c2e50eb1f044a76560093a8dcf232487c5';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ final navigationItems = {
|
|||
"/history": "History",
|
||||
"/browse": "Browse",
|
||||
"/more": "More",
|
||||
"/trackerLibrary/anilist": "AL",
|
||||
"/trackerLibrary/kitsu": "Kitsu",
|
||||
"/trackerLibrary/mal": "MAL",
|
||||
};
|
||||
|
||||
class SettingsSection extends StatelessWidget {
|
||||
|
|
|
|||
|
|
@ -149,18 +149,31 @@ class FullScreenReaderState extends _$FullScreenReaderState {
|
|||
|
||||
@riverpod
|
||||
class NavigationOrderState extends _$NavigationOrderState {
|
||||
final items = [
|
||||
'/MangaLibrary',
|
||||
'/AnimeLibrary',
|
||||
'/NovelLibrary',
|
||||
'/updates',
|
||||
'/history',
|
||||
'/browse',
|
||||
'/more',
|
||||
'/trackerLibrary/anilist',
|
||||
'/trackerLibrary/kitsu',
|
||||
'/trackerLibrary/mal',
|
||||
];
|
||||
|
||||
@override
|
||||
List<String> build() {
|
||||
return isar.settings.getSync(227)!.navigationOrder ??
|
||||
[
|
||||
'/MangaLibrary',
|
||||
'/AnimeLibrary',
|
||||
'/NovelLibrary',
|
||||
'/updates',
|
||||
'/history',
|
||||
'/browse',
|
||||
'/more',
|
||||
];
|
||||
return _checkMissingItems(
|
||||
isar.settings.getSync(227)!.navigationOrder?.toList() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
List<String> _checkMissingItems(List<String> navigationOrder) {
|
||||
navigationOrder.addAll(
|
||||
items.where((e) => !navigationOrder.contains(e)).toList(),
|
||||
);
|
||||
return navigationOrder;
|
||||
}
|
||||
|
||||
void set(List<String> values) {
|
||||
|
|
@ -176,7 +189,12 @@ class NavigationOrderState extends _$NavigationOrderState {
|
|||
class HideItemsState extends _$HideItemsState {
|
||||
@override
|
||||
List<String> build() {
|
||||
return isar.settings.getSync(227)!.hideItems ?? [];
|
||||
return isar.settings.getSync(227)!.hideItems ??
|
||||
[
|
||||
'/trackerLibrary/anilist',
|
||||
'/trackerLibrary/kitsu',
|
||||
'/trackerLibrary/mal',
|
||||
];
|
||||
}
|
||||
|
||||
void set(List<String> values) {
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ final fullScreenReaderStateProvider =
|
|||
|
||||
typedef _$FullScreenReaderState = AutoDisposeNotifier<bool>;
|
||||
String _$navigationOrderStateHash() =>
|
||||
r'f1da55a7687995d136a6580d3f63f9b1b32a6ae8';
|
||||
r'f300869743afaccfd47210115f341d25fec522bb';
|
||||
|
||||
/// See also [NavigationOrderState].
|
||||
@ProviderFor(NavigationOrderState)
|
||||
|
|
@ -174,7 +174,7 @@ final navigationOrderStateProvider =
|
|||
);
|
||||
|
||||
typedef _$NavigationOrderState = AutoDisposeNotifier<List<String>>;
|
||||
String _$hideItemsStateHash() => r'b4a467e66f6a1f9b36e4b201a10b771e0dae6a80';
|
||||
String _$hideItemsStateHash() => r'6844a05786f6c547a7cba261f742e82d871b6cb1';
|
||||
|
||||
/// See also [HideItemsState].
|
||||
@ProviderFor(HideItemsState)
|
||||
|
|
|
|||
|
|
@ -1,69 +1,55 @@
|
|||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/category.dart';
|
||||
import 'package:mangayomi/models/changed.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/download.dart';
|
||||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/track.dart';
|
||||
import 'package:mangayomi/models/track_search.dart';
|
||||
import 'package:mangayomi/models/update.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/providers/track_state_providers.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_providers.dart';
|
||||
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart';
|
||||
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
|
||||
import 'package:mangayomi/modules/widgets/bottom_text_widget.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:mangayomi/modules/library/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/library/providers/library_state_provider.dart';
|
||||
import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart';
|
||||
import 'package:mangayomi/modules/library/widgets/library_gridview_widget.dart';
|
||||
import 'package:mangayomi/modules/library/widgets/library_listview_widget.dart';
|
||||
import 'package:mangayomi/modules/library/widgets/list_tile_manga_category.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/widgets/chapter_sort_list_tile_widget.dart';
|
||||
import 'package:mangayomi/modules/widgets/error_text.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
import 'package:mangayomi/utils/global_style.dart';
|
||||
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||
|
||||
enum TrackerProviders {
|
||||
anilist(syncId: 1),
|
||||
myAnimeList(syncId: 2),
|
||||
kitsu(syncId: 3),
|
||||
trakt(syncId: 4);
|
||||
myAnimeList(syncId: 1, name: "MAL"),
|
||||
anilist(syncId: 2, name: "AL"),
|
||||
kitsu(syncId: 3, name: "Kitsu"),
|
||||
trakt(syncId: 4, name: "Trakt");
|
||||
|
||||
const TrackerProviders({required this.syncId});
|
||||
const TrackerProviders({required this.syncId, required this.name});
|
||||
|
||||
final int syncId;
|
||||
final String name;
|
||||
}
|
||||
|
||||
class TrackLibrarySection {
|
||||
String name;
|
||||
Future<List<TrackSearch>?> Function() func;
|
||||
ItemType itemType;
|
||||
|
||||
TrackLibrarySection({required this.name, required this.func});
|
||||
TrackLibrarySection({
|
||||
required this.name,
|
||||
required this.func,
|
||||
this.itemType = ItemType.manga,
|
||||
});
|
||||
}
|
||||
|
||||
class TrackerLibraryScreen extends ConsumerStatefulWidget {
|
||||
final TrackerProviders trackerProvider;
|
||||
const TrackerLibraryScreen({required this.trackerProvider, super.key});
|
||||
final String? presetInput;
|
||||
const TrackerLibraryScreen({
|
||||
required this.trackerProvider,
|
||||
required this.presetInput,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<TrackerLibraryScreen> createState() =>
|
||||
|
|
@ -77,52 +63,60 @@ class _TrackerLibraryScreenState extends ConsumerState<TrackerLibraryScreen> {
|
|||
TrackLibrarySection(
|
||||
name: "Airing Anime",
|
||||
func: fetchGeneralData(ItemType.anime),
|
||||
itemType: ItemType.anime,
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Popular Anime",
|
||||
func: fetchGeneralData(ItemType.anime, rankingType: "bypopularity"),
|
||||
itemType: ItemType.anime,
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Upcoming Anime",
|
||||
func: fetchGeneralData(ItemType.anime, rankingType: "upcoming"),
|
||||
itemType: ItemType.anime,
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Airing Manga",
|
||||
func: fetchGeneralData(ItemType.manga),
|
||||
name: "Continue watching",
|
||||
func: fetchUserData(ItemType.anime),
|
||||
itemType: ItemType.anime,
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Popular Manga",
|
||||
func: fetchGeneralData(ItemType.manga, rankingType: "bypopularity"),
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Upcoming Manga",
|
||||
func: fetchGeneralData(ItemType.manga, rankingType: "upcoming"),
|
||||
name: "Top Manga",
|
||||
func: fetchGeneralData(ItemType.manga, rankingType: "manga"),
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Continue watching",
|
||||
func: fetchUserData(ItemType.anime),
|
||||
name: "Top Manhwa",
|
||||
func: fetchGeneralData(ItemType.manga, rankingType: "manhwa"),
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Top Manhua ",
|
||||
func: fetchGeneralData(ItemType.manga, rankingType: "manhua"),
|
||||
),
|
||||
TrackLibrarySection(
|
||||
name: "Continue reading",
|
||||
func: fetchUserData(ItemType.manga),
|
||||
),
|
||||
];
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(l10n.migrate)),
|
||||
body: SuperListView.builder(
|
||||
itemCount: sections.length,
|
||||
extentPrecalculationPolicy: SuperPrecalculationPolicy(),
|
||||
itemBuilder: (context, index) {
|
||||
final section = sections[index];
|
||||
return SizedBox(
|
||||
height: 260,
|
||||
child: TrackerSectionScreen(
|
||||
section: section,
|
||||
),
|
||||
);
|
||||
},
|
||||
appBar: AppBar(title: Text(widget.trackerProvider.name)),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: SuperListView.builder(
|
||||
itemCount: sections.length,
|
||||
extentPrecalculationPolicy: SuperPrecalculationPolicy(),
|
||||
itemBuilder: (context, index) {
|
||||
final section = sections[index];
|
||||
return SizedBox(
|
||||
height: 260,
|
||||
child: TrackerSectionScreen(section: section),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -222,10 +216,9 @@ class _TrackerSectionScreenState extends State<TrackerSectionScreen> {
|
|||
scrollDirection: Axis.horizontal,
|
||||
itemCount: tracks.length,
|
||||
itemBuilder: (context, index) {
|
||||
return MigrationMangaGlobalImageCard(
|
||||
oldManga: widget.manga,
|
||||
manga: pages!.list[index],
|
||||
source: widget.source,
|
||||
return TrackerLibraryImageCard(
|
||||
track: tracks[index],
|
||||
itemType: widget.section.itemType,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -241,39 +234,35 @@ class _TrackerSectionScreenState extends State<TrackerSectionScreen> {
|
|||
}
|
||||
}
|
||||
|
||||
class MigrationMangaGlobalImageCard extends ConsumerStatefulWidget {
|
||||
final Manga oldManga;
|
||||
final MManga manga;
|
||||
final Source source;
|
||||
class TrackerLibraryImageCard extends ConsumerStatefulWidget {
|
||||
final TrackSearch track;
|
||||
final ItemType itemType;
|
||||
|
||||
const MigrationMangaGlobalImageCard({
|
||||
const TrackerLibraryImageCard({
|
||||
super.key,
|
||||
required this.oldManga,
|
||||
required this.manga,
|
||||
required this.source,
|
||||
required this.track,
|
||||
required this.itemType,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<MigrationMangaGlobalImageCard> createState() =>
|
||||
_MigrationMangaGlobalImageCardState();
|
||||
ConsumerState<TrackerLibraryImageCard> createState() =>
|
||||
_TrackerLibraryImageCardState();
|
||||
}
|
||||
|
||||
class _MigrationMangaGlobalImageCardState
|
||||
extends ConsumerState<MigrationMangaGlobalImageCard>
|
||||
with AutomaticKeepAliveClientMixin<MigrationMangaGlobalImageCard> {
|
||||
class _TrackerLibraryImageCardState
|
||||
extends ConsumerState<TrackerLibraryImageCard>
|
||||
with AutomaticKeepAliveClientMixin<TrackerLibraryImageCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final getMangaDetail = widget.manga;
|
||||
final trackData = widget.track;
|
||||
return GestureDetector(
|
||||
onTap: () => _showMigrateDialog(context, l10n),
|
||||
onTap: () => _pushMigrationScreen(context),
|
||||
child: StreamBuilder(
|
||||
stream: isar.mangas
|
||||
.filter()
|
||||
.langEqualTo(widget.source.lang)
|
||||
.nameEqualTo(getMangaDetail.name)
|
||||
.sourceEqualTo(widget.source.name)
|
||||
.itemTypeEqualTo(widget.itemType)
|
||||
.nameEqualTo(trackData.title)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
final hasData = snapshot.hasData && snapshot.data!.isNotEmpty;
|
||||
|
|
@ -297,12 +286,6 @@ class _MigrationMangaGlobalImageCardState
|
|||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
child: cachedNetworkImage(
|
||||
headers: ref.watch(
|
||||
headersProvider(
|
||||
source: widget.source.name!,
|
||||
lang: widget.source.lang!,
|
||||
),
|
||||
),
|
||||
imageUrl: toImgUrl(
|
||||
hasData
|
||||
? snapshot
|
||||
|
|
@ -311,7 +294,7 @@ class _MigrationMangaGlobalImageCardState
|
|||
.customCoverFromTracker ??
|
||||
snapshot.data!.first.imageUrl ??
|
||||
""
|
||||
: getMangaDetail.imageUrl ?? "",
|
||||
: trackData.coverUrl ?? "",
|
||||
),
|
||||
width: 110,
|
||||
height: 150,
|
||||
|
|
@ -322,7 +305,7 @@ class _MigrationMangaGlobalImageCardState
|
|||
),
|
||||
BottomTextWidget(
|
||||
fontSize: 12.0,
|
||||
text: widget.manga.name!,
|
||||
text: trackData.title!,
|
||||
isLoading: true,
|
||||
textColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
isComfortableGrid: true,
|
||||
|
|
@ -349,6 +332,20 @@ class _MigrationMangaGlobalImageCardState
|
|||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
child: Icon(Icons.star, color: context.primaryColor),
|
||||
),
|
||||
TextSpan(text: " ${trackData.score ?? "?"}"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
@ -357,254 +354,27 @@ class _MigrationMangaGlobalImageCardState
|
|||
);
|
||||
}
|
||||
|
||||
void _pushMigrationScreen(BuildContext context) {
|
||||
context.push(
|
||||
"/migrate",
|
||||
extra: Manga(
|
||||
name: widget.track.title,
|
||||
itemType: widget.itemType,
|
||||
source: null,
|
||||
author: null,
|
||||
artist: null,
|
||||
genre: [],
|
||||
imageUrl: null,
|
||||
lang: null,
|
||||
link: null,
|
||||
status: Status.unknown,
|
||||
description: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
void _showMigrateDialog(BuildContext context, dynamic l10n) {
|
||||
ref
|
||||
.watch(
|
||||
getDetailProvider(
|
||||
url: widget.manga.link!,
|
||||
source: widget.source,
|
||||
).future,
|
||||
)
|
||||
.then((preview) {
|
||||
if (context.mounted) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
return AlertDialog(
|
||||
title: Text(l10n.migrate_confirm),
|
||||
content: preview.chapters != null
|
||||
? SizedBox(
|
||||
height: ctx.height(0.5),
|
||||
width: ctx.width(1),
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.all(0),
|
||||
sliver: SuperSliverList.builder(
|
||||
itemCount: preview.chapters!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final chapter = preview.chapters![index];
|
||||
return ListTile(
|
||||
title: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
preview.chapters![index].name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Row(
|
||||
children: [
|
||||
Text(
|
||||
chapter.dateUpload == null ||
|
||||
chapter.dateUpload!.isEmpty
|
||||
? ""
|
||||
: dateFormat(
|
||||
chapter.dateUpload!,
|
||||
ref: ref,
|
||||
context: context,
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
),
|
||||
),
|
||||
if (chapter.scanlator?.isNotEmpty ??
|
||||
false)
|
||||
Row(
|
||||
children: [
|
||||
const Text(' • '),
|
||||
Text(
|
||||
chapter.scanlator!,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Text(l10n.n_chapters(0)),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(ctx);
|
||||
},
|
||||
child: Text(l10n.cancel),
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
Consumer(
|
||||
builder: (context, ref, child) => TextButton(
|
||||
onPressed: () async {
|
||||
String? historyChapter;
|
||||
String? historyDate;
|
||||
List<Chapter> chaptersProgress = [];
|
||||
isar.writeTxnSync(() {
|
||||
final histories = isar.historys
|
||||
.filter()
|
||||
.mangaIdEqualTo(widget.oldManga.id)
|
||||
.sortByDate()
|
||||
.findAllSync();
|
||||
historyChapter = _extractChapterNumber(
|
||||
histories.lastOrNull?.chapter.value?.name ??
|
||||
"",
|
||||
);
|
||||
historyDate = histories.lastOrNull?.date;
|
||||
for (var history in histories) {
|
||||
isar.historys.deleteSync(history.id!);
|
||||
ref
|
||||
.read(
|
||||
synchingProvider(syncId: 1).notifier,
|
||||
)
|
||||
.addChangedPart(
|
||||
ActionType.removeHistory,
|
||||
history.id,
|
||||
"{}",
|
||||
false,
|
||||
);
|
||||
}
|
||||
for (var chapter in widget.oldManga.chapters) {
|
||||
chaptersProgress.add(chapter);
|
||||
isar.updates
|
||||
.filter()
|
||||
.mangaIdEqualTo(chapter.mangaId)
|
||||
.chapterNameEqualTo(chapter.name)
|
||||
.deleteAllSync();
|
||||
isar.chapters.deleteSync(chapter.id!);
|
||||
ref
|
||||
.read(
|
||||
synchingProvider(syncId: 1).notifier,
|
||||
)
|
||||
.addChangedPart(
|
||||
ActionType.removeChapter,
|
||||
chapter.id,
|
||||
"{}",
|
||||
false,
|
||||
);
|
||||
}
|
||||
widget.oldManga.name = widget.manga.name;
|
||||
widget.oldManga.link = widget.manga.link;
|
||||
widget.oldManga.imageUrl =
|
||||
widget.manga.imageUrl;
|
||||
widget.oldManga.lang = widget.source.lang;
|
||||
widget.oldManga.source = widget.source.name;
|
||||
widget.oldManga.artist = preview.artist;
|
||||
widget.oldManga.author = preview.author;
|
||||
widget.oldManga.status =
|
||||
preview.status ?? widget.oldManga.status;
|
||||
widget.oldManga.description =
|
||||
preview.description;
|
||||
widget.oldManga.genre = preview.genre;
|
||||
isar.mangas.putSync(widget.oldManga);
|
||||
ref
|
||||
.read(synchingProvider(syncId: 1).notifier)
|
||||
.addChangedPart(
|
||||
ActionType.updateItem,
|
||||
widget.oldManga.id,
|
||||
widget.oldManga.toJson(),
|
||||
false,
|
||||
);
|
||||
});
|
||||
await ref.read(
|
||||
updateMangaDetailProvider(
|
||||
mangaId: widget.oldManga.id,
|
||||
isInit: false,
|
||||
).future,
|
||||
);
|
||||
isar.writeTxnSync(() {
|
||||
for (var oldChapter in chaptersProgress) {
|
||||
final chapter = isar.chapters
|
||||
.filter()
|
||||
.mangaIdEqualTo(widget.oldManga.id)
|
||||
.nameContains(
|
||||
_extractChapterNumber(
|
||||
oldChapter.name ?? "",
|
||||
) ??
|
||||
".....",
|
||||
caseSensitive: false,
|
||||
)
|
||||
.findFirstSync();
|
||||
if (chapter != null) {
|
||||
chapter.isBookmarked =
|
||||
oldChapter.isBookmarked;
|
||||
chapter.lastPageRead =
|
||||
oldChapter.lastPageRead;
|
||||
chapter.isRead = oldChapter.isRead;
|
||||
isar.chapters.putSync(chapter);
|
||||
}
|
||||
}
|
||||
final chapter = isar.chapters
|
||||
.filter()
|
||||
.mangaIdEqualTo(widget.oldManga.id)
|
||||
.nameContains(
|
||||
historyChapter ?? ".....",
|
||||
caseSensitive: false,
|
||||
)
|
||||
.findFirstSync();
|
||||
if (chapter != null) {
|
||||
isar.historys.putSync(
|
||||
History(
|
||||
mangaId: widget.oldManga.id,
|
||||
date:
|
||||
historyDate ??
|
||||
DateTime.now().millisecondsSinceEpoch
|
||||
.toString(),
|
||||
itemType: widget.oldManga.itemType,
|
||||
chapterId: chapter.id,
|
||||
)..chapter.value = chapter,
|
||||
);
|
||||
}
|
||||
});
|
||||
ref.invalidate(
|
||||
getMangaDetailStreamProvider(
|
||||
mangaId: widget.oldManga.id!,
|
||||
),
|
||||
);
|
||||
if (ctx.mounted) {
|
||||
Navigator.pop(ctx);
|
||||
Navigator.pop(ctx);
|
||||
}
|
||||
},
|
||||
child: Text(l10n.ok),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String? _extractChapterNumber(String chapterName) {
|
||||
return RegExp(
|
||||
r'\s*(\d+\.\d+)\s*',
|
||||
multiLine: true,
|
||||
).firstMatch(chapterName)?.group(0) ??
|
||||
RegExp(
|
||||
r'\s*(\d+)\s*',
|
||||
multiLine: true,
|
||||
).firstMatch(chapterName)?.group(0);
|
||||
}
|
||||
}
|
||||
|
||||
class SuperPrecalculationPolicy extends ExtentPrecalculationPolicy {
|
||||
|
|
|
|||
|
|
@ -123,8 +123,6 @@ class RouterNotifier extends ChangeNotifier {
|
|||
builder: (id) =>
|
||||
LibraryScreen(itemType: ItemType.novel, presetInput: id),
|
||||
),
|
||||
_genericRoute(name: "history", child: const HistoryScreen()),
|
||||
_genericRoute(name: "updates", child: const UpdatesScreen()),
|
||||
_genericRoute<String?>(
|
||||
name: "trackerLibrary/anilist",
|
||||
builder: (id) => TrackerLibraryScreen(
|
||||
|
|
@ -146,6 +144,8 @@ class RouterNotifier extends ChangeNotifier {
|
|||
presetInput: id,
|
||||
),
|
||||
),
|
||||
_genericRoute(name: "history", child: const HistoryScreen()),
|
||||
_genericRoute(name: "updates", child: const UpdatesScreen()),
|
||||
_genericRoute(name: "browse", child: const BrowseScreen()),
|
||||
_genericRoute(name: "more", child: const MoreScreen()),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -220,7 +220,9 @@ class MyAnimeList extends _$MyAnimeList {
|
|||
totalChapter: e["node"][contentUnit],
|
||||
coverUrl: e["node"]["main_picture"]["large"] ?? "",
|
||||
title: e["node"]["title"],
|
||||
score: e["node"]["mean"],
|
||||
score: e["node"]["mean"] is double
|
||||
? e["node"]["mean"]
|
||||
: (e["node"]["mean"] as int).toDouble(),
|
||||
startDate: e["node"]["start_date"] ?? "",
|
||||
publishingType: e["node"]["media_type"].toString().replaceAll(
|
||||
"_",
|
||||
|
|
@ -232,8 +234,12 @@ class MyAnimeList extends _$MyAnimeList {
|
|||
),
|
||||
trackingUrl:
|
||||
"https://myanimelist.net/$item/${e["node"]["id"]}",
|
||||
startedReadingDate: e["list_status"]["start_date"],
|
||||
finishedReadingDate: e["list_status"]["finish_date"],
|
||||
startedReadingDate: _parseDate(
|
||||
e["list_status"]["start_date"],
|
||||
),
|
||||
finishedReadingDate: _parseDate(
|
||||
e["list_status"]["finish_date"],
|
||||
),
|
||||
lastChapterRead:
|
||||
e["list_status"][isManga
|
||||
? "num_chapters_read"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'myanimelist.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$myAnimeListHash() => r'ecf9947e37eb0485fcc015ce002d9a440a0ecee1';
|
||||
String _$myAnimeListHash() => r'eb483b6451d34e595bb770eefc0f673df13275b3';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
Loading…
Reference in a new issue