mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-20 02:32:05 +00:00
chapter filter feature
This commit is contained in:
parent
f339e455f7
commit
cabf9fcc63
28 changed files with 1852 additions and 474 deletions
|
|
@ -1,109 +0,0 @@
|
|||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/services/cloudflare/cookie.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
|
||||
Future<dom.Document?> cloudflareBypassDom(
|
||||
{required String url, required bool bypass, required String source}) async {
|
||||
bool isOk = false;
|
||||
dom.Document? htmll;
|
||||
if (bypass == false) {
|
||||
final response = await http.get(Uri.parse(url));
|
||||
htmll = dom.Document.html(response.body);
|
||||
isOk = true;
|
||||
} else {
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
String? html;
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("https://challenges.cloudflare.com")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
htmll = dom.Document.html(html!);
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings: InAppWebViewSettings(
|
||||
userAgent: Hive.box(HiveConstant.hiveBoxAppSettings).get("ua",
|
||||
defaultValue:
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0")),
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
}
|
||||
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await setCookie(source, url);
|
||||
return htmll;
|
||||
}
|
||||
|
||||
Future<String> cloudflareBypassHtml(
|
||||
{required String url, required String source}) async {
|
||||
bool isOk = false;
|
||||
String? html;
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("Un instant…")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings: InAppWebViewSettings(
|
||||
userAgent: Hive.box(HiveConstant.hiveBoxAppSettings).get("ua",
|
||||
defaultValue:
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0")),
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await setCookie(source, url);
|
||||
return html!;
|
||||
}
|
||||
|
|
@ -2,15 +2,17 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:mangayomi/models/comick/chapter_page_comick.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/services/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/services/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
||||
|
|
@ -40,7 +42,9 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
String? zjsUrl;
|
||||
zjs() async {
|
||||
final html = await cloudflareBypassHtml(
|
||||
url: zjsUrl!, source: modelManga.source!.toLowerCase());
|
||||
url: zjsUrl!,
|
||||
source: modelManga.source!.toLowerCase(),
|
||||
useUserAgent: true);
|
||||
dom.Document htmll = dom.Document.html(baseUrl!);
|
||||
final strings = html
|
||||
.replaceAll(RegExp(r'\\[(.*?)\\]'), '')
|
||||
|
|
@ -99,23 +103,15 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
else if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||
String mangaId =
|
||||
modelManga.chapters![index].url!.split('/').last.split('-').first;
|
||||
var headers = {
|
||||
'Referer': 'https://comick.app/',
|
||||
'User-Agent':
|
||||
'Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/8\\\$userAgentRandomizer1.0.4\\\$userAgentRandomizer3.1\\\$userAgentRandomizer2 Safari/537.36'
|
||||
};
|
||||
var request = http.Request('GET',
|
||||
Uri.parse('https://api.comick.fun/chapter/$mangaId?tachiyomi=true'));
|
||||
request.headers.addAll(headers);
|
||||
http.StreamedResponse response = await request.send();
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var data = jsonDecode(await response.stream.bytesToString())
|
||||
as Map<String, dynamic>;
|
||||
var page = ChapterPageComick.fromJson(data);
|
||||
for (var url in page.chapter!.images!) {
|
||||
urll.add(url.url);
|
||||
}
|
||||
final response = await httpGet(
|
||||
url: 'https://api.comick.fun/chapter/$mangaId?tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var data = jsonDecode(response!) as Map<String, dynamic>;
|
||||
var page = ChapterPageComick.fromJson(data);
|
||||
for (var url in page.chapter!.images!) {
|
||||
urll.add(url.url);
|
||||
}
|
||||
if (!incognitoMode) {
|
||||
ref.watch(hiveBoxMangaInfo).put(
|
||||
|
|
@ -128,11 +124,11 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
/**************/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||
final dom = await cloudflareBypassDom(
|
||||
url: modelManga.chapters![index].url!,
|
||||
bypass: true,
|
||||
source: source,
|
||||
);
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: modelManga.chapters![index].url!,
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#readerarea').isNotEmpty) {
|
||||
final ta =
|
||||
dom.querySelectorAll('#readerarea').map((e) => e.outerHtml).toList();
|
||||
|
|
@ -182,18 +178,20 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
/***********/
|
||||
|
||||
else if (source == 'mangakawaii') {
|
||||
final response =
|
||||
await http.get(Uri.parse(modelManga.chapters![index].url!));
|
||||
final response = await httpGet(
|
||||
url: modelManga.chapters![index].url!,
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var chapterSlug = RegExp("""var chapter_slug = "([^"]*)";""")
|
||||
.allMatches(response.body.toString())
|
||||
.allMatches(response!)
|
||||
.last
|
||||
.group(1);
|
||||
var mangaSlug = RegExp("""var oeuvre_slug = "([^"]*)";""")
|
||||
.allMatches(response.body.toString())
|
||||
.allMatches(response)
|
||||
.last
|
||||
.group(1);
|
||||
var pages = RegExp('''"page_image":"([^"]*)"''')
|
||||
.allMatches(response.body.toString())
|
||||
.allMatches(response)
|
||||
.map((e) => e.group(1));
|
||||
|
||||
for (var tt in pages) {
|
||||
|
|
@ -212,10 +210,12 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
/***********/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||
final dom =
|
||||
await httpResToDom(url: modelManga.chapters![index].url!, headers: {});
|
||||
|
||||
if (dom.querySelectorAll('#all > .img-responsive').isNotEmpty) {
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: modelManga.chapters![index].url!,
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#all > .img-responsive').isNotEmpty) {
|
||||
urll = dom.querySelectorAll('#all > .img-responsive').map((e) {
|
||||
final RegExp regexx = RegExp(r'data-src="([^"]+)"');
|
||||
if (modelManga.source!.toLowerCase() == 'jpmangas' ||
|
||||
|
|
@ -267,14 +267,11 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
return secretKeyResultScript;
|
||||
}
|
||||
|
||||
final response = await http.get(
|
||||
Uri.parse("http://www.mangahere.cc${modelManga.chapters![index].url!}"),
|
||||
headers: {
|
||||
"Referer": "https://www.mangahere.cc/",
|
||||
"Cookie": "isAdult=1"
|
||||
});
|
||||
var link = "http://www.mangahere.cc${modelManga.chapters![index].url!}";
|
||||
dom.Document htmll = dom.Document.html(response.body);
|
||||
final response =
|
||||
await httpGet(url: link, source: source, resDom: false) as String?;
|
||||
|
||||
dom.Document htmll = dom.Document.html(response!);
|
||||
int? pagesNumber = -1;
|
||||
if (htmll.querySelectorAll('body > div > div > span > a:').isNotEmpty) {
|
||||
final ta = htmll
|
||||
|
|
@ -303,12 +300,12 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
urll.add("https:$tt");
|
||||
}
|
||||
} else {
|
||||
var secretKey = extractSecretKey(response.body, flutterJs);
|
||||
var secretKey = extractSecretKey(response, flutterJs);
|
||||
|
||||
var chapterIdStartLoc = response.body.indexOf("chapterid");
|
||||
var chapterId = response.body
|
||||
.substring(chapterIdStartLoc + 11,
|
||||
response.body.indexOf(";", chapterIdStartLoc))
|
||||
var chapterIdStartLoc = response.indexOf("chapterid");
|
||||
var chapterId = response
|
||||
.substring(
|
||||
chapterIdStartLoc + 11, response.indexOf(";", chapterIdStartLoc))
|
||||
.trim();
|
||||
|
||||
var pageBase = link.substring(0, link.lastIndexOf("/"));
|
||||
|
|
@ -360,13 +357,15 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
}
|
||||
}
|
||||
} else if (source == 'japscan') {
|
||||
final html = await cloudflareBypassHtml(
|
||||
final response = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: modelManga.chapters![index].url!,
|
||||
source: modelManga.source!.toLowerCase());
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
RegExp regex = RegExp(r'<script src="/zjs/(.*?)"');
|
||||
Match? match = regex.firstMatch(html);
|
||||
Match? match = regex.firstMatch(response!);
|
||||
String zjsurl = match!.group(1)!;
|
||||
baseUrl = html;
|
||||
baseUrl = response;
|
||||
zjsUrl = "https://www.japscan.lol/zjs/$zjsurl";
|
||||
zjs();
|
||||
await Future.doWhile(() async {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'get_manga_chapter_url.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getMangaChapterUrlHash() =>
|
||||
r'dda553ecccf269ea375550eba379f57b8ede0263';
|
||||
r'128242519581990fb05796608bc1e746d0e885df';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/models/comick/manga_chapter_detail.dart';
|
||||
import 'package:mangayomi/models/comick/manga_detail_comick.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/services/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/services/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -92,74 +94,56 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
/*comick*/
|
||||
/********/
|
||||
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.comick) {
|
||||
var headers = {
|
||||
'Referer': 'https://comick.app/',
|
||||
'User-Agent':
|
||||
'Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/8\\\$userAgentRandomizer1.0.4\\\$userAgentRandomizer3.1\\\$userAgentRandomizer2 Safari/537.36'
|
||||
};
|
||||
var request = http.Request(
|
||||
'GET', Uri.parse('https://api.comick.fun$url?tachiyomi=true'));
|
||||
final response = await httpGet(
|
||||
url: 'https://api.comick.fun$url?tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var mangaDetail = jsonDecode(response!) as Map<String, dynamic>;
|
||||
|
||||
request.headers.addAll(headers);
|
||||
var mangaDetailLMap = MangaDetailModelComick.fromJson(mangaDetail);
|
||||
|
||||
http.StreamedResponse response = await request.send();
|
||||
RegExp regExp = RegExp(r'name:\s*(.*?),');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var mangaDetail = jsonDecode(await response.stream.bytesToString())
|
||||
as Map<String, dynamic>;
|
||||
String authorr =
|
||||
regExp.firstMatch(mangaDetailLMap.authors![0].toString())?.group(1) ??
|
||||
'';
|
||||
String statuss = _parseStatut(mangaDetailLMap.comic!.status!);
|
||||
status = statuss;
|
||||
author = authorr;
|
||||
RegExp regExp1 = RegExp(r'name:\s*(.*?)}');
|
||||
for (var ok in mangaDetailLMap.genres!) {
|
||||
genre.add(regExp1.firstMatch(ok.toString())!.group(1)!);
|
||||
}
|
||||
description = mangaDetailLMap.comic!.desc;
|
||||
String tt = await findCurrentSlug(mangaDetailLMap.comic!.slug!);
|
||||
String mangaId = tt.split('":"').last.replaceAll('"}', '');
|
||||
String limit = mangaDetailLMap.comic!.chapterCount.toString();
|
||||
|
||||
var mangaDetailLMap = MangaDetailModelComick.fromJson(mangaDetail);
|
||||
|
||||
RegExp regExp = RegExp(r'name:\s*(.*?),');
|
||||
|
||||
String authorr =
|
||||
regExp.firstMatch(mangaDetailLMap.authors![0].toString())?.group(1) ??
|
||||
'';
|
||||
String statuss = _parseStatut(mangaDetailLMap.comic!.status!);
|
||||
status = statuss;
|
||||
author = authorr;
|
||||
RegExp regExp1 = RegExp(r'name:\s*(.*?)}');
|
||||
for (var ok in mangaDetailLMap.genres!) {
|
||||
genre.add(regExp1.firstMatch(ok.toString())!.group(1)!);
|
||||
}
|
||||
description = mangaDetailLMap.comic!.desc;
|
||||
String tt = await findCurrentSlug(mangaDetailLMap.comic!.slug!);
|
||||
String mangaId = tt.split('":"').last.replaceAll('"}', '');
|
||||
String limit = mangaDetailLMap.comic!.chapterCount.toString();
|
||||
|
||||
var requestt = http.Request(
|
||||
'GET',
|
||||
Uri.parse(
|
||||
'https://api.comick.fun/comic/$mangaId/chapters?lang=$lang&limit=$limit'));
|
||||
|
||||
requestt.headers.addAll(headers);
|
||||
|
||||
http.StreamedResponse responsee = await requestt.send();
|
||||
|
||||
if (responsee.statusCode == 200) {
|
||||
List<String> chapterTitles = [];
|
||||
List<String> chapterUrls = [];
|
||||
List<String> chapterDates = [];
|
||||
var chapterDetail = jsonDecode(await responsee.stream.bytesToString())
|
||||
as Map<String, dynamic>;
|
||||
var chapterDetailMap = MangaChapterModelComick.fromJson(chapterDetail);
|
||||
for (var chapter in chapterDetailMap.chapters!) {
|
||||
chapterUrls.add(
|
||||
"/comic/${mangaDetailLMap.comic!.slug}/${chapter.hid}-chapter-${chapter.chap}-en");
|
||||
chapterDates.add(chapter.createdAt!.toString().substring(0, 10));
|
||||
chapterTitles.add(beautifyChapterName(chapter.vol ?? "",
|
||||
chapter.chap ?? "", chapter.title ?? "", lang));
|
||||
}
|
||||
List<String> chapterTitless = [];
|
||||
for (var i = 0; i < chapterTitles.length; i++) {
|
||||
if (!chapterTitless.contains(chapterTitles[i])) {
|
||||
chapterTitle.add(chapterTitles[i]);
|
||||
chapterUrl.add(chapterUrls[i]);
|
||||
chapterDate.add(chapterDates[i].replaceAll('-', "/"));
|
||||
}
|
||||
chapterTitless.add(chapterTitles[i]);
|
||||
}
|
||||
final responsee = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/comic/$mangaId/chapters?lang=$lang&limit=$limit',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
List<String> chapterTitles = [];
|
||||
List<String> chapterUrls = [];
|
||||
List<String> chapterDates = [];
|
||||
var chapterDetail = jsonDecode(responsee!) as Map<String, dynamic>;
|
||||
var chapterDetailMap = MangaChapterModelComick.fromJson(chapterDetail);
|
||||
for (var chapter in chapterDetailMap.chapters!) {
|
||||
chapterUrls.add(
|
||||
"/comic/${mangaDetailLMap.comic!.slug}/${chapter.hid}-chapter-${chapter.chap}-en");
|
||||
chapterDates.add(chapter.createdAt!.toString().substring(0, 10));
|
||||
chapterTitles.add(beautifyChapterName(
|
||||
chapter.vol ?? "", chapter.chap ?? "", chapter.title ?? "", lang));
|
||||
}
|
||||
List<String> chapterTitless = [];
|
||||
for (var i = 0; i < chapterTitles.length; i++) {
|
||||
if (!chapterTitless.contains(chapterTitles[i])) {
|
||||
chapterTitle.add(chapterTitles[i]);
|
||||
chapterUrl.add(chapterUrls[i]);
|
||||
chapterDate.add(chapterDates[i].replaceAll('-', "/"));
|
||||
}
|
||||
chapterTitless.add(chapterTitles[i]);
|
||||
}
|
||||
}
|
||||
/*************/
|
||||
|
|
@ -167,8 +151,12 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
/**************/
|
||||
|
||||
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mangathemesia) {
|
||||
final dom = await httpResToDom(url: url, headers: {});
|
||||
if (dom
|
||||
final dom = await httpGet(
|
||||
url: url,
|
||||
source: source,
|
||||
resDom: true,
|
||||
useUserAgent: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'div.bigcontent, div.animefull, div.main-info, div.postbody')
|
||||
.isNotEmpty) {
|
||||
|
|
@ -294,13 +282,14 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
/*mangakawaii*/
|
||||
/***********/
|
||||
else if (source.toLowerCase() == "mangakawaii") {
|
||||
final dom = await httpResToDom(
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangakawaii.io$url',
|
||||
headers: {"Accept-Language": "fr"});
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
List detail = [];
|
||||
imageUrl =
|
||||
"https://cdn.mangakawaii.pics/uploads$url/cover/cover_250x350.jpg";
|
||||
if (dom.querySelectorAll('dd.text-justify.text-break').isNotEmpty) {
|
||||
if (dom!.querySelectorAll('dd.text-justify.text-break').isNotEmpty) {
|
||||
final tt = dom
|
||||
.querySelectorAll('dd.text-justify.text-break')
|
||||
.map((e) => e.text.trim())
|
||||
|
|
@ -408,11 +397,8 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
/***********/
|
||||
|
||||
else if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mmrcms) {
|
||||
final dom = await cloudflareBypassDom(
|
||||
url: url,
|
||||
bypass: true,
|
||||
source: source,
|
||||
);
|
||||
final dom =
|
||||
await httpGet(url: url, source: source, resDom: true) as Document?;
|
||||
description = dom!
|
||||
.querySelectorAll('.row .well p')
|
||||
.map((e) => e.text.trim())
|
||||
|
|
@ -503,14 +489,11 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
/*mangahere*/
|
||||
/***********/
|
||||
else if (source.toLowerCase() == "mangahere") {
|
||||
final dom = await httpResToDom(
|
||||
final dom = await httpGet(
|
||||
url: "http://www.mangahere.cc$url",
|
||||
headers: {
|
||||
"Referer": "https://www.mangahere.cc/",
|
||||
"Cookie": "isAdult=1"
|
||||
});
|
||||
|
||||
if (dom
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
' body > div > div > div.detail-info-right > p.detail-info-right-title > span.detail-info-right-title-tip')
|
||||
.isNotEmpty) {
|
||||
|
|
@ -596,21 +579,18 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
}
|
||||
}
|
||||
} else if (source.toLowerCase() == "japscan") {
|
||||
final htmll = await cloudflareBypassDom(
|
||||
url: url,
|
||||
bypass: true,
|
||||
source: source,
|
||||
);
|
||||
if (htmll!.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final dom =
|
||||
await httpGet(url: url, source: source, resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final images =
|
||||
htmll.querySelectorAll('.col-5 ').map((e) => e.outerHtml).toList();
|
||||
dom.querySelectorAll('.col-5 ').map((e) => e.outerHtml).toList();
|
||||
RegExp exp = RegExp(r'src="([^"]+)"');
|
||||
|
||||
String? srcValue = exp.firstMatch(images[0])?.group(1);
|
||||
imageUrl = 'https://www.japscan.me$srcValue';
|
||||
imageUrl = 'https://www.japscan.lol$srcValue';
|
||||
|
||||
if (htmll.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final stat = htmll
|
||||
if (dom.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final stat = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Statut:'))
|
||||
.map((e) => e.text)
|
||||
|
|
@ -619,7 +599,7 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
status = stat[0].replaceAll('Statut:', '').trim();
|
||||
}
|
||||
|
||||
final auth = htmll
|
||||
final auth = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Auteur(s):'))
|
||||
.map((e) => e.text)
|
||||
|
|
@ -632,7 +612,7 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
status = "";
|
||||
}
|
||||
|
||||
final genres = htmll
|
||||
final genres = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Genre(s):'))
|
||||
.map((e) => e.text.replaceAll('Genre(s):', '').trim())
|
||||
|
|
@ -643,7 +623,7 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
}
|
||||
}
|
||||
|
||||
final synop = htmll
|
||||
final synop = dom
|
||||
.querySelectorAll('p.list-group-item ')
|
||||
.map((e) => e.text.trim())
|
||||
.toList();
|
||||
|
|
@ -653,17 +633,17 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
}
|
||||
|
||||
final urls =
|
||||
htmll.querySelectorAll('.col-8 ').map((e) => e.outerHtml).toList();
|
||||
dom.querySelectorAll('.col-8 ').map((e) => e.outerHtml).toList();
|
||||
|
||||
for (var ok in urls) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
|
||||
String? srcValue = exp.firstMatch(ok)?.group(1);
|
||||
chapterUrl.add('https://www.japscan.me$srcValue');
|
||||
chapterUrl.add('https://www.japscan.lol$srcValue');
|
||||
}
|
||||
|
||||
final chapterTitlee =
|
||||
htmll.querySelectorAll('.col-8').map((e) => e.text.trim()).toList();
|
||||
dom.querySelectorAll('.col-8').map((e) => e.text.trim()).toList();
|
||||
|
||||
if (chapterTitlee.isNotEmpty) {
|
||||
for (var ok in chapterTitlee) {
|
||||
|
|
@ -672,7 +652,7 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
}
|
||||
|
||||
final chapterDatee =
|
||||
htmll.querySelectorAll('.col-4').map((e) => e.text.trim()).toList();
|
||||
dom.querySelectorAll('.col-4').map((e) => e.text.trim()).toList();
|
||||
if (chapterDatee.isNotEmpty) {
|
||||
for (var ok in chapterDatee) {
|
||||
chapterDate.add(ok);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_manga_detail.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getMangaDetailHash() => r'9fb313c606c75f308217de7bea8a771e8801e5f6';
|
||||
String _$getMangaDetailHash() => r'8cc750dd5a207747b8e97db82ce6c1b141c8419a';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/comick/popular_manga_comick.dart';
|
||||
import 'package:mangayomi/services/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_list.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -42,6 +41,16 @@ TypeSource getWpMangTypeSource(String source) {
|
|||
return typeSource!;
|
||||
}
|
||||
|
||||
bool isCloudflare(String source) {
|
||||
bool? isCloudflare;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
isCloudflare = sourcesList[i].isCloudflare;
|
||||
}
|
||||
}
|
||||
return isCloudflare!;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
||||
{required String source, required int page}) async {
|
||||
|
|
@ -54,31 +63,19 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
|||
/*comick*/
|
||||
/*******/
|
||||
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||
var headers = {
|
||||
'Referer': 'https://comick.app/',
|
||||
'User-Agent':
|
||||
'Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/8\\\$userAgentRandomizer1.0.4\\\$userAgentRandomizer3.1\\\$userAgentRandomizer2 Safari/537.36'
|
||||
};
|
||||
var request = http.Request(
|
||||
'GET',
|
||||
Uri.parse(
|
||||
'https://api.comick.fun/v1.0/search?sort=follow&page=$page&tachiyomi=true'));
|
||||
final response = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/v1.0/search?sort=follow&page=$page&tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var popularManga = jsonDecode(response!) as List;
|
||||
|
||||
request.headers.addAll(headers);
|
||||
|
||||
http.StreamedResponse response = await request.send();
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var popularManga =
|
||||
jsonDecode(await response.stream.bytesToString()) as List;
|
||||
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => PopularMangaModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => PopularMangaModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,11 +83,10 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
|||
/*mangathemesia*/
|
||||
/**************/
|
||||
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||
final dom = await cloudflareBypassDom(
|
||||
url: '${getWpMangaUrl(source)}/manga/?title=&page=$page&order=popular',
|
||||
bypass: true,
|
||||
source: source,
|
||||
);
|
||||
final dom = await httpGet(useUserAgent: true,
|
||||
url: '${getWpMangaUrl(source)}/manga/?title=&page=$page&order=popular',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
|
||||
|
|
@ -131,9 +127,11 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
|||
/*mangakawaii*/
|
||||
/***********/
|
||||
if (source == "mangakawaii") {
|
||||
final dom =
|
||||
await httpResToDom(url: 'https://www.mangakawaii.io/', headers: {});
|
||||
if (dom.querySelectorAll('a.hot-manga__item').isNotEmpty) {
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangakawaii.io/',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('a.hot-manga__item').isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll('a.hot-manga__item ')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
|
|
@ -154,12 +152,12 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
|||
/***********/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||
final dom = await httpResToDom(
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'${getWpMangaUrl(source)}/filterList?page=$page&sortBy=views&asc=false',
|
||||
headers: {});
|
||||
|
||||
final urlElement = dom.getElementsByClassName('chart-title');
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
final urlElement = dom!.getElementsByClassName('chart-title');
|
||||
for (var e in urlElement) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.outerHtml);
|
||||
|
|
@ -180,9 +178,11 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
|||
/*mangahere*/
|
||||
/***********/
|
||||
else if (source == "mangahere") {
|
||||
final dom = await httpResToDom(
|
||||
url: 'https://www.mangahere.cc/ranking/', headers: {});
|
||||
if (dom
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangahere.cc/ranking/',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'body > div.container.weekrank.ranking > div > div > ul > li > a')
|
||||
.isNotEmpty) {
|
||||
|
|
@ -209,21 +209,20 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
|||
.toList();
|
||||
}
|
||||
} else if (source == "japscan") {
|
||||
final htmll = await cloudflareBypassDom(
|
||||
url: "https://www.japscan.lol/",
|
||||
bypass: true,
|
||||
source: source,
|
||||
);
|
||||
if (htmll!.querySelectorAll('#top_mangas_week > ul > li ').isNotEmpty) {
|
||||
final urls = htmll
|
||||
final dom = await httpGet(
|
||||
url: "https://www.japscan.lol/",
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#top_mangas_week > ul > li ').isNotEmpty) {
|
||||
final urls = dom
|
||||
.querySelectorAll('#top_mangas_week > ul > li > a')
|
||||
.where((e) => e.attributes['href'].toString().contains('manga'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
for (var ok in urls) {
|
||||
url.add("https://www.japscan.me$ok");
|
||||
url.add("https://www.japscan.lol$ok");
|
||||
}
|
||||
name = htmll
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'#top_mangas_week > ul > li > a.text-dark.font-weight-bold')
|
||||
.map((e) => e.innerHtml)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_popular_manga.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getPopularMangaHash() => r'cc0567f4659ae10b5e55ccdbb5f5a9560cc09a16';
|
||||
String _$getPopularMangaHash() => r'87a02e32e79c310e6717e7ae95bf54fdd13b2a00';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
106
lib/services/http_service/cloudflare/cloudflare_bypass.dart
Normal file
106
lib/services/http_service/cloudflare/cloudflare_bypass.dart
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cookie.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
|
||||
Future<dom.Document?> cloudflareBypassDom(
|
||||
{required String url,
|
||||
required bool bypass,
|
||||
required String source,
|
||||
required bool useUserAgent}) async {
|
||||
log(source);
|
||||
bool isOk = false;
|
||||
dom.Document? htmll;
|
||||
final ua = Hive.box(HiveConstant.hiveBoxAppSettings)
|
||||
.get("ua", defaultValue: defaultUserAgent);
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
String? html;
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("https://challenges.cloudflare.com")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
htmll = dom.Document.html(html!);
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings: useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await setCookie(source, url);
|
||||
return htmll;
|
||||
}
|
||||
|
||||
Future<String> cloudflareBypassHtml(
|
||||
{required String url,
|
||||
required String source,
|
||||
required bool useUserAgent}) async {
|
||||
final ua = Hive.box(HiveConstant.hiveBoxAppSettings)
|
||||
.get("ua", defaultValue: defaultUserAgent);
|
||||
bool isOk = false;
|
||||
String? html;
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("Un instant…")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings: useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await setCookie(source, url);
|
||||
return html!;
|
||||
}
|
||||
|
|
@ -6,3 +6,4 @@ Future<Document> httpResToDom(
|
|||
final response = await http.get(Uri.parse(url), headers: headers);
|
||||
return Document.html(response.body);
|
||||
}
|
||||
|
||||
40
lib/services/http_service/http_service.dart
Normal file
40
lib/services/http_service/http_service.dart
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/services/http_service/http_res_to_dom_html.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
|
||||
Future<dynamic> httpGet(
|
||||
{required String url,
|
||||
required String source,
|
||||
required bool resDom,
|
||||
bool useUserAgent = false}) async {
|
||||
bool isCloudflaree = isCloudflare(source);
|
||||
if (resDom) {
|
||||
Document? dom;
|
||||
if (isCloudflaree) {
|
||||
dom = await cloudflareBypassDom(
|
||||
url: url,
|
||||
bypass: isCloudflaree,
|
||||
source: source,
|
||||
useUserAgent: useUserAgent);
|
||||
} else {
|
||||
dom = await httpResToDom(url: url, headers: headers(source));
|
||||
}
|
||||
return dom;
|
||||
} else {
|
||||
String? resHtml;
|
||||
if (isCloudflaree) {
|
||||
resHtml = await cloudflareBypassHtml(
|
||||
url: url,
|
||||
source: source,
|
||||
useUserAgent: useUserAgent,
|
||||
);
|
||||
} else {
|
||||
final response = await http.get(Uri.parse(url), headers: headers(source));
|
||||
resHtml = response.body;
|
||||
}
|
||||
return resHtml;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
import 'dart:convert';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/models/comick/search_manga_cimick.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/services/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'search_manga.g.dart';
|
||||
|
|
@ -31,30 +33,18 @@ Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
|||
/*comick*/
|
||||
/********/
|
||||
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||
var headers = {
|
||||
'Referer': 'https://comick.app/',
|
||||
'User-Agent':
|
||||
'Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/8\\\$userAgentRandomizer1.0.4\\\$userAgentRandomizer3.1\\\$userAgentRandomizer2 Safari/537.36'
|
||||
};
|
||||
var request = http.Request(
|
||||
'GET',
|
||||
Uri.parse(
|
||||
'https://api.comick.fun/search?q=${query.trim()}&tachiyomi=true&page=1'));
|
||||
|
||||
request.headers.addAll(headers);
|
||||
|
||||
http.StreamedResponse response = await request.send();
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var popularManga =
|
||||
jsonDecode(await response.stream.bytesToString()) as List;
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => MangaSearchModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
final response = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/search?q=${query.trim()}&tachiyomi=true&page=1',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var popularManga = jsonDecode(response!) as List;
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => MangaSearchModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,10 +52,11 @@ Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
|||
/*mangathemesia*/
|
||||
/***************/
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||
final dom = await httpResToDom(
|
||||
url: '${getWpMangaUrl(source)}/?s=${query.trim()}', headers: {});
|
||||
|
||||
if (dom
|
||||
final dom = await httpGet(
|
||||
url: '${getWpMangaUrl(source)}/?s=${query.trim()}',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'#content > div > div.postbody > div > div.listupd > div > div > a')
|
||||
.isNotEmpty) {
|
||||
|
|
@ -95,12 +86,12 @@ Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
|||
/*mangakawaii*/
|
||||
/***********/
|
||||
else if (source == "mangakawaii") {
|
||||
final dom = await httpResToDom(
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'https://www.mangakawaii.io/search?query=${query.trim()}&search_type=manga',
|
||||
headers: {'Accept-Language': 'fr'});
|
||||
|
||||
if (dom
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.isNotEmpty) {
|
||||
|
|
@ -129,9 +120,11 @@ Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
|||
/*mmrcms*/
|
||||
/***********/
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||
final response = await http.get(
|
||||
Uri.parse('${getWpMangaUrl(source)}/search?query=${query.trim()}'));
|
||||
final rep = jsonDecode(response.body);
|
||||
final response = await httpGet(
|
||||
url: '${getWpMangaUrl(source)}/search?query=${query.trim()}',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
final rep = jsonDecode(response!);
|
||||
for (var ok in rep['suggestions']) {
|
||||
if (source == 'Read Comics Online') {
|
||||
url.add('${getWpMangaUrl(source)}/comic/${ok['data']}');
|
||||
|
|
@ -148,11 +141,13 @@ Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
|||
/*mangahere*/
|
||||
/***********/
|
||||
else if (source == "mangahere") {
|
||||
final dom = await httpResToDom(
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'${getWpMangaUrl(source)}/search?title=${query.trim()}&genres=&nogenres=&sort=&stype=1&name=&type=0&author_method=cw&author=&artist_method=cw&artist=&rating_method=eq&rating=&released_method=eq&released=&st=0',
|
||||
headers: {});
|
||||
if (dom
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
|
||||
.isNotEmpty) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'search_manga.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$searchMangaHash() => r'b2376a19c02cbe43ad7f41357caeae3e7f2a210e';
|
||||
String _$searchMangaHash() => r'8efe07dbe0f844d9d17ecf6962ac7f03ebcc9d57';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/services/cloudflare/cookie.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cookie.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
|
|
@ -142,7 +141,7 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
|
|||
userAgent: Hive.box(HiveConstant.hiveBoxAppSettings).get(
|
||||
"ua",
|
||||
defaultValue:
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0")),
|
||||
defaultUserAgent)),
|
||||
initialUrlRequest:
|
||||
URLRequest(url: WebUri.uri(Uri.parse(widget.url))),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -157,7 +157,8 @@ List<SourceModel> sourcesList = [
|
|||
lang: "en",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl:
|
||||
'https://arenascans.net/wp-content/uploads/2023/02/arena-logo-1.png'),
|
||||
'https://arenascans.net/wp-content/uploads/2023/02/arena-logo-1.png',
|
||||
isCloudflare: true),
|
||||
SourceModel(
|
||||
sourceName: "AzureScans",
|
||||
url: "https://azuremanga.com",
|
||||
|
|
@ -214,7 +215,7 @@ List<SourceModel> sourcesList = [
|
|||
url: "https://void-scans.com",
|
||||
lang: "en",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: ''),
|
||||
logoUrl: '',isCloudflare: true),
|
||||
SourceModel(
|
||||
sourceName: "Kiryuu",
|
||||
url: "https://kiryuu.id",
|
||||
|
|
@ -349,7 +350,8 @@ List<SourceModel> sourcesList = [
|
|||
url: "https://sushiscan.net",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: 'https://sushiscan.net/wp-content/uploads/SushiScanNewLogo.png'),
|
||||
logoUrl: 'https://sushiscan.net/wp-content/uploads/SushiScanNewLogo.png',
|
||||
isCloudflare: true),
|
||||
SourceModel(
|
||||
sourceName: "TsundokuTraduções",
|
||||
url: "https://tsundoku.com.br",
|
||||
|
|
@ -426,6 +428,6 @@ List<SourceModel> sourcesList = [
|
|||
url: "https://japscan.lol",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.single,
|
||||
logoUrl: ''),
|
||||
|
||||
logoUrl: '',
|
||||
isCloudflare: true),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -21,17 +21,21 @@ class SourceModel extends HiveObject {
|
|||
final String logoUrl;
|
||||
@HiveField(8, defaultValue: false)
|
||||
final bool isFullData;
|
||||
@HiveField(9, defaultValue: false)
|
||||
final bool isCloudflare;
|
||||
|
||||
SourceModel(
|
||||
{required this.sourceName,
|
||||
required this.url,
|
||||
required this.lang,
|
||||
required this.typeSource,
|
||||
required this.logoUrl,
|
||||
this.isActive = true,
|
||||
this.isAdded = false,
|
||||
this.isNsfw = false,
|
||||
this.isFullData = false});
|
||||
SourceModel({
|
||||
required this.sourceName,
|
||||
required this.url,
|
||||
required this.lang,
|
||||
required this.typeSource,
|
||||
required this.logoUrl,
|
||||
this.isActive = true,
|
||||
this.isAdded = false,
|
||||
this.isNsfw = false,
|
||||
this.isFullData = false,
|
||||
this.isCloudflare = false,
|
||||
});
|
||||
}
|
||||
|
||||
@HiveType(typeId: 4)
|
||||
|
|
|
|||
|
|
@ -26,13 +26,14 @@ class SourceModelAdapter extends TypeAdapter<SourceModel> {
|
|||
isAdded: fields[4] == null ? false : fields[4] as bool,
|
||||
isNsfw: fields[5] == null ? false : fields[5] as bool,
|
||||
isFullData: fields[8] == null ? false : fields[8] as bool,
|
||||
isCloudflare: fields[9] == null ? false : fields[9] as bool,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, SourceModel obj) {
|
||||
writer
|
||||
..writeByte(9)
|
||||
..writeByte(10)
|
||||
..writeByte(0)
|
||||
..write(obj.sourceName)
|
||||
..writeByte(1)
|
||||
|
|
@ -50,7 +51,9 @@ class SourceModelAdapter extends TypeAdapter<SourceModel> {
|
|||
..writeByte(7)
|
||||
..write(obj.logoUrl)
|
||||
..writeByte(8)
|
||||
..write(obj.isFullData);
|
||||
..write(obj.isFullData)
|
||||
..writeByte(9)
|
||||
..write(obj.isCloudflare);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -9,3 +9,6 @@ class HiveConstant {
|
|||
static String get hiveBoxReaderSettings => "_reader_box_settings_";
|
||||
static String get hiveBoxReaderMode => "_readerMode_box_settings_";
|
||||
}
|
||||
|
||||
const defaultUserAgent =
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0";
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
|
||||
|
|
@ -5,9 +7,9 @@ Map<String, String> headers(String source) {
|
|||
source = source.toLowerCase();
|
||||
final cookie = Hive.box(HiveConstant.hiveBoxAppSettings)
|
||||
.get("$source-cookie", defaultValue: "");
|
||||
final userAgent = Hive.box(HiveConstant.hiveBoxAppSettings).get("ua",
|
||||
defaultValue:
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0");
|
||||
log(cookie);
|
||||
final userAgent = Hive.box(HiveConstant.hiveBoxAppSettings)
|
||||
.get("ua", defaultValue: defaultUserAgent);
|
||||
return source == 'mangakawaii'
|
||||
? {
|
||||
'Referer': 'https://www.mangakawaii.io/',
|
||||
|
|
@ -33,5 +35,5 @@ Map<String, String> headers(String source) {
|
|||
'Referer': "https://www.sushscan.net/",
|
||||
"Cookie": cookie
|
||||
}
|
||||
: {};
|
||||
: {'User-Agent': userAgent, "Cookie": cookie};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
List<ModelManga> bookmark() {
|
||||
List<ModelManga> mang = [];
|
||||
for (var entry in entries) {
|
||||
final d = entry.chapters!.where((element) => element.isBookmarked == true);
|
||||
final d =
|
||||
entry.chapters!.where((element) => element.isBookmarked == true);
|
||||
List<ModelChapters> chap = [];
|
||||
for (var a in d) {
|
||||
chap.add(a);
|
||||
|
|
@ -100,23 +101,25 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
});
|
||||
_textEditingController.clear();
|
||||
},
|
||||
icon: Icon(Icons.search, color: Theme.of(context).hintColor)),
|
||||
icon: Icon(
|
||||
Icons.search,
|
||||
)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
_showModalSort();
|
||||
},
|
||||
icon: Icon(Icons.filter_list_sharp,
|
||||
color: Theme.of(context).hintColor)),
|
||||
// PopupMenuButton(
|
||||
// color: Theme.of(context).hintColor,
|
||||
// itemBuilder: (context) {
|
||||
// return [
|
||||
// const PopupMenuItem<int>(
|
||||
// value: 0, child: Text("Open random entry")),
|
||||
// ];
|
||||
// },
|
||||
// onSelected: (value) {}),
|
||||
icon: Icon(
|
||||
Icons.filter_list_sharp,
|
||||
)),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Open random entry")),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {}),
|
||||
],
|
||||
),
|
||||
body: ValueListenableBuilder<Box<ModelManga>>(
|
||||
|
|
|
|||
|
|
@ -14,8 +14,11 @@ import 'package:mangayomi/utils/media_query.dart';
|
|||
import 'package:mangayomi/utils/utils.dart';
|
||||
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
||||
import 'package:mangayomi/views/manga/detail/readmore.dart';
|
||||
import 'package:mangayomi/views/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/views/manga/detail/widgets/chapter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/views/manga/detail/widgets/chapter_sort_list_tile_widget.dart';
|
||||
import 'package:mangayomi/views/manga/download/providers/download_provider.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
|
||||
class MangaDetailView extends ConsumerStatefulWidget {
|
||||
final Function(bool) isExtended;
|
||||
|
|
@ -54,11 +57,44 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
bool isOk = false;
|
||||
bool _expanded = false;
|
||||
ScrollController _scrollController = ScrollController();
|
||||
|
||||
late int _pageLength = ref
|
||||
.read(chapterFilterResultStateProvider(modelManga: widget.modelManga!)
|
||||
.notifier)
|
||||
.getData()
|
||||
.chapters!
|
||||
.length +
|
||||
1;
|
||||
late List<ModelChapters>? _chapters = ref
|
||||
.read(chapterFilterResultStateProvider(modelManga: widget.modelManga!)
|
||||
.notifier)
|
||||
.getData()
|
||||
.chapters;
|
||||
late ModelManga? _modelManga = ref
|
||||
.read(chapterFilterResultStateProvider(modelManga: widget.modelManga!)
|
||||
.notifier)
|
||||
.getData();
|
||||
|
||||
_refreshData() {
|
||||
final modelManga = ref
|
||||
.read(chapterFilterResultStateProvider(modelManga: widget.modelManga!)
|
||||
.notifier)
|
||||
.getData();
|
||||
|
||||
setState(() {
|
||||
_pageLength = modelManga.chapters!.length + 1;
|
||||
_chapters = modelManga.chapters;
|
||||
_modelManga = modelManga;
|
||||
});
|
||||
}
|
||||
|
||||
bool isRefresh = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final chapterIndexList = ref.watch(chapterIndexListStateProvider);
|
||||
final chapterNameList = ref.watch(chapterNameListStateProvider);
|
||||
final isLongPressed = ref.watch(isLongPressedStateProvider);
|
||||
final reverse = ref.watch(reverseMangaStateProvider);
|
||||
final reverse =
|
||||
ref.watch(reverseMangaStateProvider(modelManga: widget.modelManga!));
|
||||
final chapter = ref.watch(chapterModelStateProvider);
|
||||
return NotificationListener<UserScrollNotification>(
|
||||
onNotification: (notification) {
|
||||
|
|
@ -78,12 +114,12 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
? Container(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
child: AppBar(
|
||||
title: Text(chapterIndexList.length.toString()),
|
||||
title: Text(chapterNameList.length.toString()),
|
||||
backgroundColor: generalColor(context).withOpacity(0.2),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.read(chapterNameListStateProvider.notifier)
|
||||
.clear();
|
||||
|
||||
ref
|
||||
|
|
@ -98,23 +134,25 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
ref
|
||||
.read(chapterIndexListStateProvider
|
||||
.notifier)
|
||||
.selectAll(i);
|
||||
.read(
|
||||
chapterNameListStateProvider.notifier)
|
||||
.selectAll(widget
|
||||
.modelManga!.chapters![i].name!);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.select_all)),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
if (widget.modelManga!.chapters!.length ==
|
||||
chapterIndexList.length) {
|
||||
chapterNameList.length) {
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
ref
|
||||
.read(chapterIndexListStateProvider
|
||||
.read(chapterNameListStateProvider
|
||||
.notifier)
|
||||
.selectSome(i);
|
||||
.selectSome(widget
|
||||
.modelManga!.chapters![i].name!);
|
||||
}
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
|
|
@ -124,9 +162,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
ref
|
||||
.read(chapterIndexListStateProvider
|
||||
.read(chapterNameListStateProvider
|
||||
.notifier)
|
||||
.selectSome(i);
|
||||
.selectSome(widget
|
||||
.modelManga!.chapters![i].name!);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -145,23 +184,32 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
? Colors.transparent
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
actions: [
|
||||
// IconButton(
|
||||
// splashRadius: 20,
|
||||
// onPressed: () {},
|
||||
// icon: Icon(Icons.download_outlined,
|
||||
// color: Theme.of(context).hintColor)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {},
|
||||
icon: Icon(
|
||||
Icons.download_outlined,
|
||||
)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(reverseMangaStateProvider.notifier)
|
||||
.update(!reverse);
|
||||
_showModalSort();
|
||||
},
|
||||
icon: Icon(
|
||||
reverse
|
||||
? Icons.arrow_downward_sharp
|
||||
: Icons.arrow_upward_sharp,
|
||||
color: Theme.of(context).hintColor)),
|
||||
Icons.filter_list_sharp,
|
||||
)),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Edit categories")),
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Migrate")),
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Share")),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {}),
|
||||
],
|
||||
)),
|
||||
body: Stack(
|
||||
|
|
@ -213,29 +261,37 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
child: ListView.builder(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.only(top: 0, bottom: 60),
|
||||
itemCount: widget.listLength,
|
||||
itemCount: _pageLength,
|
||||
itemBuilder: (context, index) {
|
||||
int finalIndex = index - 1;
|
||||
if (index == 0) {
|
||||
return _bodyContainer();
|
||||
}
|
||||
if (isRefresh) {
|
||||
final modelManga = ref
|
||||
.read(chapterFilterResultStateProvider(
|
||||
modelManga: widget.modelManga!)
|
||||
.notifier)
|
||||
.getData();
|
||||
|
||||
int reverseIndex = widget
|
||||
.modelManga!.chapters!.length -
|
||||
widget.modelManga!.chapters!.reversed
|
||||
.toList()
|
||||
.indexOf(widget
|
||||
.modelManga!.chapters!.reversed
|
||||
.toList()[finalIndex]) -
|
||||
_pageLength = modelManga.chapters!.length + 1;
|
||||
_chapters = modelManga.chapters;
|
||||
_modelManga = modelManga;
|
||||
isRefresh = false;
|
||||
}
|
||||
|
||||
int reverseIndex = _chapters!.length -
|
||||
_chapters!.reversed.toList().indexOf(
|
||||
_chapters!.reversed.toList()[finalIndex]) -
|
||||
1;
|
||||
|
||||
List<ModelChapters> chapters = reverse
|
||||
? widget.modelManga!.chapters!.reversed.toList()
|
||||
: widget.modelManga!.chapters!;
|
||||
? _chapters!.reversed.toList()
|
||||
: _chapters!;
|
||||
|
||||
return ChapterListTileWidget(
|
||||
chapters: chapters,
|
||||
modelManga: widget.modelManga!,
|
||||
modelManga: _modelManga!,
|
||||
reverse: reverse,
|
||||
reverseIndex: reverseIndex,
|
||||
finalIndex: finalIndex,
|
||||
|
|
@ -263,7 +319,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent),
|
||||
onPressed: () async {
|
||||
for (var idx in chapterIndexList) {
|
||||
for (var name in chapterNameList) {
|
||||
List<ModelChapters> chap = [];
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
|
|
@ -280,18 +336,19 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
name: entries.chapters![i].name,
|
||||
url: entries.chapters![i].url,
|
||||
dateUpload: entries.chapters![i].dateUpload,
|
||||
isBookmarked: idx == i
|
||||
? entries.chapters![i].isBookmarked
|
||||
? false
|
||||
: true
|
||||
: entries.chapters![i].isBookmarked,
|
||||
isBookmarked:
|
||||
name == entries.chapters![i].name
|
||||
? entries.chapters![i].isBookmarked
|
||||
? false
|
||||
: true
|
||||
: entries.chapters![i].isBookmarked,
|
||||
scanlator: entries.chapters![i].scanlator,
|
||||
isRead: entries.chapters![i].isRead,
|
||||
lastPageRead:
|
||||
entries.chapters![i].lastPageRead));
|
||||
}
|
||||
|
||||
// print(chapterIndexList);
|
||||
// print(chapterNameList);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga!.imageUrl,
|
||||
name: widget.modelManga!.name,
|
||||
|
|
@ -312,11 +369,13 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
'${widget.modelManga!.lang}-${widget.modelManga!.link}',
|
||||
model);
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.read(chapterNameListStateProvider.notifier)
|
||||
.clear();
|
||||
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
isRefresh = true;
|
||||
}
|
||||
},
|
||||
child: Icon(chapter.isBookmarked
|
||||
|
|
@ -331,7 +390,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent),
|
||||
onPressed: () {
|
||||
for (var idx in chapterIndexList) {
|
||||
for (var name in chapterNameList) {
|
||||
List<ModelChapters> chap = [];
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
|
|
@ -351,7 +410,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
isBookmarked:
|
||||
entries.chapters![i].isBookmarked,
|
||||
scanlator: entries.chapters![i].scanlator,
|
||||
isRead: idx == i
|
||||
isRead: name == entries.chapters![i].name
|
||||
? entries.chapters![i].isRead
|
||||
? false
|
||||
: true
|
||||
|
|
@ -380,11 +439,12 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
'${widget.modelManga!.lang}-${widget.modelManga!.link}',
|
||||
model);
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.read(chapterNameListStateProvider.notifier)
|
||||
.clear();
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
isRefresh = true;
|
||||
}
|
||||
},
|
||||
child: Icon(chapter.isRead
|
||||
|
|
@ -399,7 +459,19 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent),
|
||||
onPressed: () {
|
||||
for (var idx in chapterIndexList) {
|
||||
List<int> indexList = [];
|
||||
for (var name in chapterNameList) {
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
if (widget.modelManga!.chapters![i].name ==
|
||||
name) {
|
||||
indexList.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var idx in indexList) {
|
||||
final entries = ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.values
|
||||
|
|
@ -423,7 +495,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.read(chapterNameListStateProvider.notifier)
|
||||
.clear();
|
||||
},
|
||||
child: const Icon(Icons.download_outlined)),
|
||||
|
|
@ -435,6 +507,142 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
));
|
||||
}
|
||||
|
||||
_showModalSort() {
|
||||
late TabController tabBarController;
|
||||
showMaterialModalBottomSheet(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(5), topRight: Radius.circular(5))),
|
||||
enableDrag: true,
|
||||
expand: false,
|
||||
context: context,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (context) {
|
||||
if (!isOk) {
|
||||
tabBarController = TabController(length: 3, vsync: this);
|
||||
tabBarController.animateTo(0);
|
||||
}
|
||||
return SizedBox(
|
||||
height: mediaHeight(context, 0.25),
|
||||
child: DefaultTabController(
|
||||
length: 3,
|
||||
child: Scaffold(
|
||||
body: Column(
|
||||
children: [
|
||||
TabBar(
|
||||
controller: tabBarController,
|
||||
tabs: const [
|
||||
Tab(text: "Filter"),
|
||||
Tab(text: "Sort"),
|
||||
Tab(text: "Display"),
|
||||
],
|
||||
),
|
||||
Flexible(
|
||||
child: TabBarView(
|
||||
controller: tabBarController,
|
||||
children: [
|
||||
Consumer(builder: (context, ref, chil) {
|
||||
return Column(
|
||||
children: [
|
||||
ListTileChapterFilter(
|
||||
label: "Downloaded",
|
||||
type: ref.watch(
|
||||
chapterFilterDownloadedStateProvider(
|
||||
modelManga:
|
||||
widget.modelManga!)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
chapterFilterDownloadedStateProvider(
|
||||
modelManga: widget
|
||||
.modelManga!)
|
||||
.notifier)
|
||||
.update();
|
||||
_refreshData();
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
label: "Unread",
|
||||
type: ref.watch(
|
||||
chapterFilterUnreadStateProvider(
|
||||
modelManga:
|
||||
widget.modelManga!)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
chapterFilterUnreadStateProvider(
|
||||
modelManga: widget
|
||||
.modelManga!)
|
||||
.notifier)
|
||||
.update();
|
||||
_refreshData();
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
label: "Bookmark",
|
||||
type: ref.watch(
|
||||
chapterFilterBookmarkStateProvider(
|
||||
modelManga:
|
||||
widget.modelManga!)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
chapterFilterBookmarkStateProvider(
|
||||
modelManga: widget
|
||||
.modelManga!)
|
||||
.notifier)
|
||||
.update();
|
||||
_refreshData();
|
||||
}),
|
||||
],
|
||||
);
|
||||
}),
|
||||
Consumer(builder: (context, ref, chil) {
|
||||
final reverse = ref.watch(
|
||||
reverseMangaStateProvider(
|
||||
modelManga: widget.modelManga!));
|
||||
return Column(
|
||||
children: [
|
||||
ListTileChapterSort(
|
||||
label: "By upload date",
|
||||
reverse: reverse,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(reverseMangaStateProvider(
|
||||
modelManga:
|
||||
widget.modelManga!)
|
||||
.notifier)
|
||||
.update(!reverse);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}),
|
||||
Consumer(builder: (context, ref, chil) {
|
||||
return Column(
|
||||
children: [
|
||||
RadioListTile(
|
||||
title: Text("Source title"),
|
||||
value: "e",
|
||||
groupValue: "e",
|
||||
selected: true,
|
||||
onChanged: (value) {},
|
||||
),
|
||||
RadioListTile(
|
||||
title: Text("Chapter number"),
|
||||
value: "ej",
|
||||
groupValue: "e",
|
||||
selected: false,
|
||||
onChanged: (value) {},
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
)));
|
||||
});
|
||||
}
|
||||
|
||||
Widget _bodyContainer() {
|
||||
return Stack(
|
||||
children: [
|
||||
|
|
@ -574,7 +782,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
'${widget.modelManga!.chapters!.length.toString()} chapters',
|
||||
'${(_pageLength - 1)} chapters',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'state_providers.g.dart';
|
||||
|
||||
|
|
@ -24,13 +25,13 @@ class ChapterModelState extends _$ChapterModelState {
|
|||
}
|
||||
|
||||
@riverpod
|
||||
class ChapterIndexListState extends _$ChapterIndexListState {
|
||||
class ChapterNameListState extends _$ChapterNameListState {
|
||||
@override
|
||||
List<int> build() {
|
||||
List<String> build() {
|
||||
return [];
|
||||
}
|
||||
|
||||
void update(int value) {
|
||||
void update(String value) {
|
||||
var newList = state.reversed.toList();
|
||||
if (newList.contains(value)) {
|
||||
newList.remove(value);
|
||||
|
|
@ -43,7 +44,7 @@ class ChapterIndexListState extends _$ChapterIndexListState {
|
|||
state = newList;
|
||||
}
|
||||
|
||||
void selectAll(int value) {
|
||||
void selectAll(String value) {
|
||||
var newList = state.reversed.toList();
|
||||
if (!newList.contains(value)) {
|
||||
newList.add(value);
|
||||
|
|
@ -52,7 +53,7 @@ class ChapterIndexListState extends _$ChapterIndexListState {
|
|||
state = newList;
|
||||
}
|
||||
|
||||
void selectSome(int value) {
|
||||
void selectSome(String value) {
|
||||
var newList = state.reversed.toList();
|
||||
if (newList.contains(value)) {
|
||||
newList.remove(value);
|
||||
|
|
@ -94,11 +95,567 @@ class IsExtendedState extends _$IsExtendedState {
|
|||
@riverpod
|
||||
class ReverseMangaState extends _$ReverseMangaState {
|
||||
@override
|
||||
bool build() {
|
||||
return false;
|
||||
bool build({required ModelManga modelManga}) {
|
||||
return ref.watch(hiveBoxSettings).get(
|
||||
"${modelManga.source}/${modelManga.name}-reverseManga",
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
void update(bool value) {
|
||||
ref
|
||||
.watch(hiveBoxSettings)
|
||||
.put("${modelManga.source}/${modelManga.name}-reverseManga", value);
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class ChapterFilterDownloadedState extends _$ChapterFilterDownloadedState {
|
||||
@override
|
||||
int build({required ModelManga modelManga}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return ref.watch(hiveBoxSettings).get(
|
||||
"${modelManga.source}/${modelManga.name}-sortChapterDownload",
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
ref.watch(hiveBoxSettings).put(
|
||||
"${modelManga.source}/${modelManga.name}-sortChapterDownload", type);
|
||||
state = type;
|
||||
}
|
||||
|
||||
ModelManga getData() {
|
||||
if (getType() == 1) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
final modelChapDownload = ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.get(chapters[i].name, defaultValue: null);
|
||||
if (modelChapDownload != null && modelChapDownload.isDownload == true) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
|
||||
return model;
|
||||
} else if (getType() == 2) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
final modelChapDownload = ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.get(chapters[i].name, defaultValue: null);
|
||||
if (!(modelChapDownload != null &&
|
||||
modelChapDownload.isDownload == true)) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
|
||||
return model;
|
||||
} else {
|
||||
return modelManga;
|
||||
}
|
||||
}
|
||||
|
||||
ModelManga update() {
|
||||
if (state == 0) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
final modelChapDownload = ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.get(chapters[i].name, defaultValue: null);
|
||||
if (modelChapDownload != null && modelChapDownload.isDownload == true) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
setType(1);
|
||||
return model;
|
||||
} else if (state == 1) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
final modelChapDownload = ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.get(chapters[i].name, defaultValue: null);
|
||||
if (!(modelChapDownload != null &&
|
||||
modelChapDownload.isDownload == true)) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
setType(2);
|
||||
return model;
|
||||
} else {
|
||||
setType(0);
|
||||
return modelManga;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class ChapterFilterUnreadState extends _$ChapterFilterUnreadState {
|
||||
@override
|
||||
int build({required ModelManga modelManga}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return ref.watch(hiveBoxSettings).get(
|
||||
"${modelManga.source}/${modelManga.name}-sortChapterUnread",
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
ref
|
||||
.watch(hiveBoxSettings)
|
||||
.put("${modelManga.source}/${modelManga.name}-sortChapterUnread", type);
|
||||
state = type;
|
||||
}
|
||||
|
||||
ModelManga getData() {
|
||||
if (getType() == 1) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (!chapters[i].isRead) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
|
||||
return model;
|
||||
} else if (getType() == 2) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (chapters[i].isRead) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
|
||||
return model;
|
||||
} else {
|
||||
return modelManga;
|
||||
}
|
||||
}
|
||||
|
||||
ModelManga update() {
|
||||
if (state == 0) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (!chapters[i].isRead) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
setType(1);
|
||||
return model;
|
||||
} else if (state == 1) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (chapters[i].isRead) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
setType(2);
|
||||
return model;
|
||||
} else {
|
||||
setType(0);
|
||||
return modelManga;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class ChapterFilterBookmarkState extends _$ChapterFilterBookmarkState {
|
||||
@override
|
||||
int build({required ModelManga modelManga}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return ref.watch(hiveBoxSettings).get(
|
||||
"${modelManga.source}/${modelManga.name}-sortChapterBookMark",
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
ref.watch(hiveBoxSettings).put(
|
||||
"${modelManga.source}/${modelManga.name}-sortChapterBookMark", type);
|
||||
state = type;
|
||||
}
|
||||
|
||||
ModelManga getData() {
|
||||
if (getType() == 1) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (chapters[i].isBookmarked) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
|
||||
return model;
|
||||
} else if (getType() == 2) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (!chapters[i].isBookmarked) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
|
||||
return model;
|
||||
} else {
|
||||
return modelManga;
|
||||
}
|
||||
}
|
||||
|
||||
ModelManga update() {
|
||||
if (state == 0) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (chapters[i].isBookmarked) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
setType(1);
|
||||
return model;
|
||||
} else if (state == 1) {
|
||||
List<ModelChapters> chap = [];
|
||||
final chapters = modelManga.chapters;
|
||||
for (var i = 0; i < chapters!.length; i++) {
|
||||
if (!chapters[i].isBookmarked) {
|
||||
chap.add(ModelChapters(
|
||||
name: chapters[i].name,
|
||||
url: chapters[i].url,
|
||||
dateUpload: chapters[i].dateUpload,
|
||||
isBookmarked: chapters[i].isBookmarked,
|
||||
scanlator: chapters[i].scanlator,
|
||||
isRead: chapters[i].isRead,
|
||||
lastPageRead: chapters[i].lastPageRead));
|
||||
}
|
||||
}
|
||||
final model = ModelManga(
|
||||
imageUrl: modelManga.imageUrl,
|
||||
name: modelManga.name,
|
||||
genre: modelManga.genre,
|
||||
author: modelManga.author,
|
||||
description: modelManga.description,
|
||||
status: modelManga.status,
|
||||
favorite: modelManga.favorite,
|
||||
link: modelManga.link,
|
||||
source: modelManga.source,
|
||||
lang: modelManga.lang,
|
||||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chap,
|
||||
category: modelManga.category,
|
||||
lastRead: modelManga.lastRead);
|
||||
setType(2);
|
||||
return model;
|
||||
} else {
|
||||
setType(0);
|
||||
return modelManga;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class ChapterFilterResultState extends _$ChapterFilterResultState {
|
||||
@override
|
||||
ModelManga build({required ModelManga modelManga}) {
|
||||
final data1 = ref
|
||||
.read(
|
||||
chapterFilterDownloadedStateProvider(modelManga: modelManga).notifier)
|
||||
.getData();
|
||||
|
||||
final data2 = ref
|
||||
.read(chapterFilterUnreadStateProvider(modelManga: data1).notifier)
|
||||
.getData();
|
||||
|
||||
final data3 = ref
|
||||
.read(chapterFilterBookmarkStateProvider(modelManga: data2).notifier)
|
||||
.getData();
|
||||
|
||||
return data3;
|
||||
}
|
||||
|
||||
ModelManga getData() {
|
||||
final data1 = ref
|
||||
.read(
|
||||
chapterFilterDownloadedStateProvider(modelManga: modelManga).notifier)
|
||||
.getData();
|
||||
|
||||
final data2 = ref
|
||||
.read(chapterFilterUnreadStateProvider(modelManga: data1).notifier)
|
||||
.getData();
|
||||
|
||||
final data3 = ref
|
||||
.read(chapterFilterBookmarkStateProvider(modelManga: data2).notifier)
|
||||
.getData();
|
||||
|
||||
return data3;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,23 +22,23 @@ final chapterModelStateProvider =
|
|||
);
|
||||
|
||||
typedef _$ChapterModelState = AutoDisposeNotifier<ModelChapters>;
|
||||
String _$chapterIndexListStateHash() =>
|
||||
r'cef615a9638df5a2a72c6087f479824cc169a70e';
|
||||
String _$chapterNameListStateHash() =>
|
||||
r'7ad81711d912271910489528b88b8d473c1d9c60';
|
||||
|
||||
/// See also [ChapterIndexListState].
|
||||
@ProviderFor(ChapterIndexListState)
|
||||
final chapterIndexListStateProvider =
|
||||
AutoDisposeNotifierProvider<ChapterIndexListState, List<int>>.internal(
|
||||
ChapterIndexListState.new,
|
||||
name: r'chapterIndexListStateProvider',
|
||||
/// See also [ChapterNameListState].
|
||||
@ProviderFor(ChapterNameListState)
|
||||
final chapterNameListStateProvider =
|
||||
AutoDisposeNotifierProvider<ChapterNameListState, List<String>>.internal(
|
||||
ChapterNameListState.new,
|
||||
name: r'chapterNameListStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$chapterIndexListStateHash,
|
||||
: _$chapterNameListStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ChapterIndexListState = AutoDisposeNotifier<List<int>>;
|
||||
typedef _$ChapterNameListState = AutoDisposeNotifier<List<String>>;
|
||||
String _$isLongPressedStateHash() =>
|
||||
r'26fe435e8381046a30e3f6c4495303946aa3aaa7';
|
||||
|
||||
|
|
@ -72,20 +72,517 @@ final isExtendedStateProvider =
|
|||
);
|
||||
|
||||
typedef _$IsExtendedState = AutoDisposeNotifier<bool>;
|
||||
String _$reverseMangaStateHash() => r'bb1372869f122059ef962b9ff71d84e9f42bbe3b';
|
||||
String _$reverseMangaStateHash() => r'f00b2dac8e461bd1f1a32fbf1ce4994ac4d96529';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$ReverseMangaState extends BuildlessAutoDisposeNotifier<bool> {
|
||||
late final ModelManga modelManga;
|
||||
|
||||
bool build({
|
||||
required ModelManga modelManga,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ReverseMangaState].
|
||||
@ProviderFor(ReverseMangaState)
|
||||
final reverseMangaStateProvider =
|
||||
AutoDisposeNotifierProvider<ReverseMangaState, bool>.internal(
|
||||
ReverseMangaState.new,
|
||||
name: r'reverseMangaStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$reverseMangaStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
const reverseMangaStateProvider = ReverseMangaStateFamily();
|
||||
|
||||
typedef _$ReverseMangaState = AutoDisposeNotifier<bool>;
|
||||
/// See also [ReverseMangaState].
|
||||
class ReverseMangaStateFamily extends Family<bool> {
|
||||
/// See also [ReverseMangaState].
|
||||
const ReverseMangaStateFamily();
|
||||
|
||||
/// See also [ReverseMangaState].
|
||||
ReverseMangaStateProvider call({
|
||||
required ModelManga modelManga,
|
||||
}) {
|
||||
return ReverseMangaStateProvider(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ReverseMangaStateProvider getProviderOverride(
|
||||
covariant ReverseMangaStateProvider provider,
|
||||
) {
|
||||
return call(
|
||||
modelManga: provider.modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'reverseMangaStateProvider';
|
||||
}
|
||||
|
||||
/// See also [ReverseMangaState].
|
||||
class ReverseMangaStateProvider
|
||||
extends AutoDisposeNotifierProviderImpl<ReverseMangaState, bool> {
|
||||
/// See also [ReverseMangaState].
|
||||
ReverseMangaStateProvider({
|
||||
required this.modelManga,
|
||||
}) : super.internal(
|
||||
() => ReverseMangaState()..modelManga = modelManga,
|
||||
from: reverseMangaStateProvider,
|
||||
name: r'reverseMangaStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$reverseMangaStateHash,
|
||||
dependencies: ReverseMangaStateFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ReverseMangaStateFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final ModelManga modelManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ReverseMangaStateProvider && other.modelManga == modelManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, modelManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
||||
@override
|
||||
bool runNotifierBuild(
|
||||
covariant ReverseMangaState notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$chapterFilterDownloadedStateHash() =>
|
||||
r'9c0937b3deaa6982ec7a8c9ab5d55a99a059cd80';
|
||||
|
||||
abstract class _$ChapterFilterDownloadedState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
late final ModelManga modelManga;
|
||||
|
||||
int build({
|
||||
required ModelManga modelManga,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterDownloadedState].
|
||||
@ProviderFor(ChapterFilterDownloadedState)
|
||||
const chapterFilterDownloadedStateProvider =
|
||||
ChapterFilterDownloadedStateFamily();
|
||||
|
||||
/// See also [ChapterFilterDownloadedState].
|
||||
class ChapterFilterDownloadedStateFamily extends Family<int> {
|
||||
/// See also [ChapterFilterDownloadedState].
|
||||
const ChapterFilterDownloadedStateFamily();
|
||||
|
||||
/// See also [ChapterFilterDownloadedState].
|
||||
ChapterFilterDownloadedStateProvider call({
|
||||
required ModelManga modelManga,
|
||||
}) {
|
||||
return ChapterFilterDownloadedStateProvider(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ChapterFilterDownloadedStateProvider getProviderOverride(
|
||||
covariant ChapterFilterDownloadedStateProvider provider,
|
||||
) {
|
||||
return call(
|
||||
modelManga: provider.modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'chapterFilterDownloadedStateProvider';
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterDownloadedState].
|
||||
class ChapterFilterDownloadedStateProvider
|
||||
extends AutoDisposeNotifierProviderImpl<ChapterFilterDownloadedState, int> {
|
||||
/// See also [ChapterFilterDownloadedState].
|
||||
ChapterFilterDownloadedStateProvider({
|
||||
required this.modelManga,
|
||||
}) : super.internal(
|
||||
() => ChapterFilterDownloadedState()..modelManga = modelManga,
|
||||
from: chapterFilterDownloadedStateProvider,
|
||||
name: r'chapterFilterDownloadedStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$chapterFilterDownloadedStateHash,
|
||||
dependencies: ChapterFilterDownloadedStateFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ChapterFilterDownloadedStateFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final ModelManga modelManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ChapterFilterDownloadedStateProvider &&
|
||||
other.modelManga == modelManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, modelManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
||||
@override
|
||||
int runNotifierBuild(
|
||||
covariant ChapterFilterDownloadedState notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$chapterFilterUnreadStateHash() =>
|
||||
r'98e86b05fdcb874b551329ffdf322681f46fb6ce';
|
||||
|
||||
abstract class _$ChapterFilterUnreadState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
late final ModelManga modelManga;
|
||||
|
||||
int build({
|
||||
required ModelManga modelManga,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterUnreadState].
|
||||
@ProviderFor(ChapterFilterUnreadState)
|
||||
const chapterFilterUnreadStateProvider = ChapterFilterUnreadStateFamily();
|
||||
|
||||
/// See also [ChapterFilterUnreadState].
|
||||
class ChapterFilterUnreadStateFamily extends Family<int> {
|
||||
/// See also [ChapterFilterUnreadState].
|
||||
const ChapterFilterUnreadStateFamily();
|
||||
|
||||
/// See also [ChapterFilterUnreadState].
|
||||
ChapterFilterUnreadStateProvider call({
|
||||
required ModelManga modelManga,
|
||||
}) {
|
||||
return ChapterFilterUnreadStateProvider(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ChapterFilterUnreadStateProvider getProviderOverride(
|
||||
covariant ChapterFilterUnreadStateProvider provider,
|
||||
) {
|
||||
return call(
|
||||
modelManga: provider.modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'chapterFilterUnreadStateProvider';
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterUnreadState].
|
||||
class ChapterFilterUnreadStateProvider
|
||||
extends AutoDisposeNotifierProviderImpl<ChapterFilterUnreadState, int> {
|
||||
/// See also [ChapterFilterUnreadState].
|
||||
ChapterFilterUnreadStateProvider({
|
||||
required this.modelManga,
|
||||
}) : super.internal(
|
||||
() => ChapterFilterUnreadState()..modelManga = modelManga,
|
||||
from: chapterFilterUnreadStateProvider,
|
||||
name: r'chapterFilterUnreadStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$chapterFilterUnreadStateHash,
|
||||
dependencies: ChapterFilterUnreadStateFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ChapterFilterUnreadStateFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final ModelManga modelManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ChapterFilterUnreadStateProvider &&
|
||||
other.modelManga == modelManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, modelManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
||||
@override
|
||||
int runNotifierBuild(
|
||||
covariant ChapterFilterUnreadState notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$chapterFilterBookmarkStateHash() =>
|
||||
r'6fb5d0d506bc209bb6d6fea8e665f511b8ef0e8f';
|
||||
|
||||
abstract class _$ChapterFilterBookmarkState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
late final ModelManga modelManga;
|
||||
|
||||
int build({
|
||||
required ModelManga modelManga,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterBookmarkState].
|
||||
@ProviderFor(ChapterFilterBookmarkState)
|
||||
const chapterFilterBookmarkStateProvider = ChapterFilterBookmarkStateFamily();
|
||||
|
||||
/// See also [ChapterFilterBookmarkState].
|
||||
class ChapterFilterBookmarkStateFamily extends Family<int> {
|
||||
/// See also [ChapterFilterBookmarkState].
|
||||
const ChapterFilterBookmarkStateFamily();
|
||||
|
||||
/// See also [ChapterFilterBookmarkState].
|
||||
ChapterFilterBookmarkStateProvider call({
|
||||
required ModelManga modelManga,
|
||||
}) {
|
||||
return ChapterFilterBookmarkStateProvider(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ChapterFilterBookmarkStateProvider getProviderOverride(
|
||||
covariant ChapterFilterBookmarkStateProvider provider,
|
||||
) {
|
||||
return call(
|
||||
modelManga: provider.modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'chapterFilterBookmarkStateProvider';
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterBookmarkState].
|
||||
class ChapterFilterBookmarkStateProvider
|
||||
extends AutoDisposeNotifierProviderImpl<ChapterFilterBookmarkState, int> {
|
||||
/// See also [ChapterFilterBookmarkState].
|
||||
ChapterFilterBookmarkStateProvider({
|
||||
required this.modelManga,
|
||||
}) : super.internal(
|
||||
() => ChapterFilterBookmarkState()..modelManga = modelManga,
|
||||
from: chapterFilterBookmarkStateProvider,
|
||||
name: r'chapterFilterBookmarkStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$chapterFilterBookmarkStateHash,
|
||||
dependencies: ChapterFilterBookmarkStateFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ChapterFilterBookmarkStateFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final ModelManga modelManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ChapterFilterBookmarkStateProvider &&
|
||||
other.modelManga == modelManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, modelManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
||||
@override
|
||||
int runNotifierBuild(
|
||||
covariant ChapterFilterBookmarkState notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$chapterFilterResultStateHash() =>
|
||||
r'ddb83c55bbbbd00178f582875a9b72fcec0eae5a';
|
||||
|
||||
abstract class _$ChapterFilterResultState
|
||||
extends BuildlessAutoDisposeNotifier<ModelManga> {
|
||||
late final ModelManga modelManga;
|
||||
|
||||
ModelManga build({
|
||||
required ModelManga modelManga,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterResultState].
|
||||
@ProviderFor(ChapterFilterResultState)
|
||||
const chapterFilterResultStateProvider = ChapterFilterResultStateFamily();
|
||||
|
||||
/// See also [ChapterFilterResultState].
|
||||
class ChapterFilterResultStateFamily extends Family<ModelManga> {
|
||||
/// See also [ChapterFilterResultState].
|
||||
const ChapterFilterResultStateFamily();
|
||||
|
||||
/// See also [ChapterFilterResultState].
|
||||
ChapterFilterResultStateProvider call({
|
||||
required ModelManga modelManga,
|
||||
}) {
|
||||
return ChapterFilterResultStateProvider(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ChapterFilterResultStateProvider getProviderOverride(
|
||||
covariant ChapterFilterResultStateProvider provider,
|
||||
) {
|
||||
return call(
|
||||
modelManga: provider.modelManga,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'chapterFilterResultStateProvider';
|
||||
}
|
||||
|
||||
/// See also [ChapterFilterResultState].
|
||||
class ChapterFilterResultStateProvider extends AutoDisposeNotifierProviderImpl<
|
||||
ChapterFilterResultState, ModelManga> {
|
||||
/// See also [ChapterFilterResultState].
|
||||
ChapterFilterResultStateProvider({
|
||||
required this.modelManga,
|
||||
}) : super.internal(
|
||||
() => ChapterFilterResultState()..modelManga = modelManga,
|
||||
from: chapterFilterResultStateProvider,
|
||||
name: r'chapterFilterResultStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$chapterFilterResultStateHash,
|
||||
dependencies: ChapterFilterResultStateFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ChapterFilterResultStateFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final ModelManga modelManga;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ChapterFilterResultStateProvider &&
|
||||
other.modelManga == modelManga;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, modelManga.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
||||
@override
|
||||
ModelManga runNotifierBuild(
|
||||
covariant ChapterFilterResultState notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
modelManga: modelManga,
|
||||
);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ListTileChapterFilter extends StatelessWidget {
|
||||
final String label;
|
||||
final int type;
|
||||
final VoidCallback onTap;
|
||||
const ListTileChapterFilter(
|
||||
{super.key,
|
||||
required this.label,
|
||||
required this.type,
|
||||
required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
iconColor: Theme.of(context).primaryColor,
|
||||
dense: true,
|
||||
leading: type == 0
|
||||
? SizedBox(
|
||||
height: 20, width: 20, child: Icon(Icons.check_box_outline_blank))
|
||||
: type == 1
|
||||
? SizedBox(height: 20, width: 20, child: Icon(Icons.check_box))
|
||||
: Stack(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: Icon(Icons.check_box_outline_blank)),
|
||||
Positioned(
|
||||
top: 3,
|
||||
left: 2,
|
||||
right: 0,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(2)),
|
||||
height: 18,
|
||||
width: 17,
|
||||
child: Icon(
|
||||
Icons.clear,
|
||||
color: Colors.black,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
title: Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -28,10 +28,10 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final idx = reverse ? reverseIndex : finalIndex;
|
||||
final chapterIndexList = ref.watch(chapterIndexListStateProvider);
|
||||
|
||||
final chapterNameList = ref.watch(chapterNameListStateProvider);
|
||||
final chapterName = modelManga.chapters![idx].name;
|
||||
return Container(
|
||||
color: chapterIndexList.contains(idx)
|
||||
color: chapterNameList.contains(chapterName)
|
||||
? generalColor(context).withOpacity(0.4)
|
||||
: null,
|
||||
child: ListTile(
|
||||
|
|
@ -45,7 +45,9 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
: Colors.white,
|
||||
onLongPress: () {
|
||||
if (!isLongPressed) {
|
||||
ref.read(chapterIndexListStateProvider.notifier).update(idx);
|
||||
ref
|
||||
.read(chapterNameListStateProvider.notifier)
|
||||
.update(chapterName!);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chapters[finalIndex]);
|
||||
|
|
@ -53,7 +55,9 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(!isLongPressed);
|
||||
} else {
|
||||
ref.read(chapterIndexListStateProvider.notifier).update(idx);
|
||||
ref
|
||||
.read(chapterNameListStateProvider.notifier)
|
||||
.update(chapterName!);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chapters[finalIndex]);
|
||||
|
|
@ -61,7 +65,9 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
},
|
||||
onTap: () async {
|
||||
if (isLongPressed) {
|
||||
ref.read(chapterIndexListStateProvider.notifier).update(idx);
|
||||
ref
|
||||
.read(chapterNameListStateProvider.notifier)
|
||||
.update(chapterName!);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chapters[finalIndex]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ListTileChapterSort extends StatelessWidget {
|
||||
final String label;
|
||||
final bool reverse;
|
||||
final VoidCallback onTap;
|
||||
const ListTileChapterSort(
|
||||
{super.key,
|
||||
required this.label,
|
||||
required this.reverse,
|
||||
required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
iconColor: Theme.of(context).primaryColor,
|
||||
dense: true,
|
||||
leading: Icon(
|
||||
reverse ? Icons.arrow_downward_sharp : Icons.arrow_upward_sharp,
|
||||
color: Theme.of(context).hintColor),
|
||||
title: Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -182,7 +182,7 @@ class CurrentIndexProvider
|
|||
}
|
||||
}
|
||||
|
||||
String _$readerControllerHash() => r'01306848356204f0716ab763839d6c9e66051dd1';
|
||||
String _$readerControllerHash() => r'2528e56dfbf71a996ceeada7075eff571b621080';
|
||||
|
||||
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
|
||||
late final MangaReaderModel mangaReaderModel;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'flex_scheme_color_state_provider.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$flexSchemeColorStateHash() =>
|
||||
r'8d5b648c7b6d4d86f2a484bed97477b82112cc9e';
|
||||
r'825680702e419e5eb921e251312ffd4ba3303a2c';
|
||||
|
||||
/// See also [FlexSchemeColorState].
|
||||
@ProviderFor(FlexSchemeColorState)
|
||||
|
|
|
|||
Loading…
Reference in a new issue