mangathemesia multi source , impl search feature

This commit is contained in:
kodjodevf 2023-04-09 16:59:37 +01:00
parent 933ba5461c
commit 1ea161c615
20 changed files with 679 additions and 19 deletions

View file

@ -10,7 +10,7 @@ import 'package:mangayomi/views/general/general_screen.dart';
import 'package:mangayomi/views/history/history_screen.dart';
import 'package:mangayomi/views/library/library_screen.dart';
import 'package:mangayomi/views/manga/detail/manga_reader_detail.dart';
import 'package:mangayomi/views/manga/home/home.dart';
import 'package:mangayomi/views/manga/home/mang_home_screen.dart';
import 'package:mangayomi/views/manga/reader/manga_reader_view.dart';
import 'package:mangayomi/views/more/more_screen.dart';
import 'package:mangayomi/views/more/settings/appearance/appearance_screen.dart';

View file

@ -6,6 +6,9 @@ import 'package:http/http.dart' as http;
import 'package:html/dom.dart' as dom;
import 'package:mangayomi/models/model_manga.dart';
import 'package:mangayomi/providers/hive_provider.dart';
import 'package:mangayomi/services/get_popular_manga.dart';
import 'package:mangayomi/services/http_res_to_dom_html.dart';
import 'package:mangayomi/source/source_model.dart';
import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter_js/flutter_js.dart';
@ -37,6 +40,52 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
"${pathh!.path}/${modelManga.source}/${modelManga.name}/${modelManga.chapterTitle![index]}/");
if (hiveUrl.isNotEmpty) {
urll = hiveUrl;
} else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
final htmll =
await httpResToDom(url: modelManga.chapterUrl![index], headers: {});
if (htmll.querySelectorAll('#readerarea').isNotEmpty) {
final ta = htmll
.querySelectorAll('#readerarea')
.map((e) => e.outerHtml)
.toList();
final RegExp regex = RegExp(r'<img[^>]+src="([^"]+)"');
final Iterable<Match> matches = regex.allMatches(ta.first);
final List<String?> urls = matches.map((m) => m.group(1)).toList();
Iterable<Match> matchess = [];
if (htmll.querySelectorAll(' #select-paged ').isNotEmpty) {
final ee = htmll
.querySelectorAll(' #select-paged ')
.map((e) => e.outerHtml)
.toList();
final RegExp regexx = RegExp(r'value="([^"]+)"');
matchess = regexx.allMatches(ee.first);
}
final List<String?> urlss = matchess.map((m) => m.group(1)).toList();
if (urls.length == 1 && urls.isNotEmpty) {
for (var i = 0; i < urlss.length; i++) {
if (urlss[i]!.length == 1) {
urll.add(
urls.first!.replaceAll("001", '00${int.parse(urlss[i]!) + 1}'));
} else if (urlss[i]!.length == 2) {
urll.add(
urls.first!.replaceAll("001", '0${int.parse(urlss[i]!) + 1}'));
} else if (urlss[i]!.length == 3) {
urll.add(
urls.first!.replaceAll("001", '${int.parse(urlss[i]!) + 1}'));
}
}
} else if (urls.length > 1 && urls.isNotEmpty) {
for (var tt in urls) {
urll.add(tt);
}
}
ref.watch(hiveBoxMangaInfo).put(
"${modelManga.source}/${modelManga.name}/${modelManga.chapterTitle![index]}-pageurl",
urll);
}
}
/***********/
/*mangahere*/

View file

@ -7,7 +7,7 @@ part of 'get_manga_chapter_url.dart';
// **************************************************************************
String _$getMangaChapterUrlHash() =>
r'38cf836814df00df1a3a269c0c2fc0c85debff78';
r'a41949b68549e776832151d8b3a595db72fabdd9';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -1,6 +1,8 @@
import 'dart:async';
import 'dart:developer';
import 'package:mangayomi/services/get_popular_manga.dart';
import 'package:mangayomi/services/http_res_to_dom_html.dart';
import 'package:mangayomi/source/source_model.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'get_manga_detail.g.dart';
@ -46,7 +48,130 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
List<String> chapterDate = [];
source = source.toLowerCase();
String? description;
if (source == "mangahere") {
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
final dom = await httpResToDom(url: url, headers: {});
if (dom
.querySelectorAll(
'div.bigcontent, div.animefull, div.main-info, div.postbody')
.isNotEmpty) {
final resHtml = dom.querySelector(
'div.bigcontent, div.animefull, div.main-info, div.postbody');
if (resHtml!.querySelectorAll('.tsinfo .imptdt').isNotEmpty) {
status = resHtml
.querySelectorAll('.tsinfo .imptdt')
.where((e) =>
e.innerHtml.contains("Status") ||
e.innerHtml.contains("Situação"))
.map((e) => e.innerHtml.contains("Situação")
? e.text.replaceAll('Situação', '').trim()
: e.text.replaceAll('Status', '').trim())
.toList()
.last;
} else if (resHtml.querySelectorAll('.infotable tr').isNotEmpty) {
status = resHtml
.querySelectorAll('.infotable tr')
.where((e) =>
e.innerHtml.toLowerCase().contains('statut') ||
e.innerHtml.toLowerCase().contains('status'))
.map((e) => e.querySelector('td:last-child')!.text)
.toList()
.first;
} else if (resHtml.querySelectorAll('.fmed').isNotEmpty) {
status = resHtml
.querySelectorAll('.tsinfo .imptdt')
.map((e) => e.text.replaceAll('Status', '').trim())
.toList()
.first;
} else {
status = "";
}
//2
if (resHtml.querySelectorAll('.fmed').isNotEmpty) {
author = resHtml
.querySelectorAll('.fmed')
.where((e) => e.innerHtml.contains("Author"))
.map((e) => e.text.replaceAll('Author', '').trim())
.toList()
.first;
} else if (resHtml.querySelectorAll('.tsinfo .imptdt').isNotEmpty) {
author = resHtml
.querySelectorAll('.tsinfo .imptdt')
.where((e) =>
e.innerHtml.contains("Author") ||
e.innerHtml.contains("Auteur") ||
e.innerHtml.contains("Autor"))
.map((e) => e.innerHtml.contains("Autor")
? e.text.replaceAll('Autor', '').trim()
: e.innerHtml.contains("Autheur")
? e.text.replaceAll('Auteur', '').trim()
: e.text.replaceAll('Author', '').trim())
.toList()
.first;
} else if (resHtml.querySelectorAll('.infotable tr').isNotEmpty) {
author = resHtml
.querySelectorAll('.infotable tr')
.where((e) =>
e.innerHtml.toLowerCase().contains('auteur') ||
e.innerHtml.toLowerCase().contains('author'))
.map((e) => e.querySelector('td:last-child')!.text)
.toList()
.first;
} else {
author = "";
}
description = resHtml
.querySelector(".desc, .entry-content[itemprop=description]")!
.text;
if (resHtml
.querySelectorAll('div.gnr a, .mgen a, .seriestugenre a')
.isNotEmpty) {
final tt = resHtml
.querySelectorAll('div.gnr a, .mgen a, .seriestugenre a')
.map((e) => e.text.trim())
.toList();
for (var ok in tt) {
genre.add(ok);
}
} else {
genre.add('');
}
if (resHtml.querySelectorAll('#chapterlist a').isNotEmpty) {
final udl = resHtml
.querySelectorAll('#chapterlist a ')
.where((e) => e.attributes.containsKey('href'))
.map((e) => e.attributes['href'])
.toList();
for (var ok in udl) {
chapterUrl.add(ok!);
}
}
if (resHtml.querySelectorAll('.lch a, .chapternum').isNotEmpty) {
final tt = resHtml
.querySelectorAll('.lch a, .chapternum')
.map((e) => e.text.trim())
.toList();
tt.removeWhere((element) => element.contains('{{number}}'));
for (var ok in tt) {
chapterTitle.add(ok.trimLeft());
}
}
if (resHtml.querySelectorAll('.chapterdate').isNotEmpty) {
final tt = resHtml
.querySelectorAll('.chapterdate')
.map((e) => e.text.trim())
.toList();
tt.removeWhere((element) => element.contains('{{date}}'));
for (var ok in tt) {
chapterDate.add(ok);
}
}
}
} else if (source == "mangahere") {
final dom = await httpResToDom(
url: "http://www.mangahere.cc$url",
headers: {

View file

@ -6,7 +6,7 @@ part of 'get_manga_detail.dart';
// RiverpodGenerator
// **************************************************************************
String _$getMangaDetailHash() => r'bbaec699742fa0b06f698d9c3be501564d9a9352';
String _$getMangaDetailHash() => r'4b0dd5315b3a1270722494045a7f9e3a3f455484';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -1,5 +1,7 @@
import 'dart:async';
import 'package:mangayomi/services/http_res_to_dom_html.dart';
import 'package:mangayomi/source/source_list.dart';
import 'package:mangayomi/source/source_model.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'get_popular_manga.g.dart';
@ -14,6 +16,26 @@ class GetMangaModel {
});
}
String getWpMangaUrl(String source) {
String url = "";
for (var i = 0; i < sourcesList.length; i++) {
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
url = sourcesList[i].url;
}
}
return url;
}
TypeSource getWpMangTypeSource(String source) {
TypeSource? typeSource;
for (var i = 0; i < sourcesList.length; i++) {
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
typeSource = sourcesList[i].typeSource;
}
}
return typeSource!;
}
@riverpod
Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
{required String source, required int page}) async {
@ -21,6 +43,46 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
List<String?> name = [];
List<String?> image = [];
source = source.toLowerCase();
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
final dom = await httpResToDom(
url: '${getWpMangaUrl(source)}/manga/?title=&page=$page&order=popular',
headers: {});
if (dom
.querySelectorAll(
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
.isNotEmpty) {
url = dom
.querySelectorAll(
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
.map((e) {
RegExp exp = RegExp(r'href="([^"]+)"');
Iterable<Match> matches = exp.allMatches(e.innerHtml);
String? firstMatch = matches.first.group(1);
return firstMatch;
}).toList();
image = dom
.querySelectorAll(
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
.map((e) {
RegExp exp = RegExp(r'src="([^"]+)"');
Iterable<Match> matches = exp.allMatches(e.innerHtml);
String? firstMatch = matches.first.group(1);
return firstMatch;
}).toList();
name = dom
.querySelectorAll(
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx ')
.map((e) {
RegExp exp = RegExp(r'title="([^"]+)"');
Iterable<Match> matches = exp.allMatches(e.innerHtml);
String? firstMatch = matches.first.group(1);
return firstMatch;
}).toList();
}
} else
//mangahere
if (source == "mangahere") {
final dom = await httpResToDom(

View file

@ -6,7 +6,7 @@ part of 'get_popular_manga.dart';
// RiverpodGenerator
// **************************************************************************
String _$getPopularMangaHash() => r'0b6445ff81dbbe1d337f37ed46544f5834805088';
String _$getPopularMangaHash() => r'5addb8826c01045b532a53de957c6470294833ad';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -0,0 +1,96 @@
import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:html/dom.dart' as dom;
import 'package:mangayomi/services/get_popular_manga.dart';
import 'package:mangayomi/services/http_res_to_dom_html.dart';
import 'package:mangayomi/source/source_model.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'search_manga.g.dart';
class SearchMangaModel {
late List<String?> url;
late List<String?> name;
late List<String?> image;
SearchMangaModel({
required this.name,
required this.url,
required this.image,
});
}
@riverpod
Future<SearchMangaModel> searchManga(SearchMangaRef ref,
{required String source, required String query}) async {
List<String?> url = [];
List<String?> name = [];
List<String?> image = [];
source = source.toLowerCase();
//mangathemesia
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
final dom = await httpResToDom(
url: '${getWpMangaUrl(source)}/?s=${query.trim()}', headers: {});
if (dom
.querySelectorAll(
'#content > div > div.postbody > div > div.listupd > div > div > a')
.isNotEmpty) {
url = dom
.querySelectorAll(
'#content > div > div.postbody > div > div.listupd > div > div > a ')
.where((e) => e.attributes.containsKey('href'))
.map((e) => e.attributes['href'])
.toList();
image = dom
.querySelectorAll(
' #content > div > div.postbody > div > div.listupd > div > div > a > div > img')
.where((e) => e.attributes.containsKey('src'))
.map((e) => e.attributes['src'])
.toList();
name = dom
.querySelectorAll(
'#content > div > div.postbody > div > div.listupd > div > div > a ')
.where((e) => e.attributes.containsKey('title'))
.map((e) => e.attributes['title'])
.toList();
}
}
//mangahere
else if (source == "mangahere") {
log("message");
final dom = await httpResToDom(
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
.querySelectorAll(
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
.isNotEmpty) {
url = dom
.querySelectorAll(
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
.where((e) => e.attributes.containsKey('href'))
.map((e) => e.attributes['href'])
.toList();
image = dom
.querySelectorAll(
'body > div.container > div > div > ul > li > a > img')
.where((e) => e.attributes.containsKey('src'))
.where((e) => e.attributes['src']!.contains("cover"))
.map((e) => e.attributes['src'])
.toList();
name = dom
.querySelectorAll(
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
.where((e) => e.attributes.containsKey('title'))
.map((e) => e.attributes['title'])
.toList();
}
}
return SearchMangaModel(name: name, url: url, image: image);
}

View file

@ -0,0 +1,121 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'search_manga.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$searchMangaHash() => r'18866e3523f085404fecaa91fa3bc1a7149724e6';
/// 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));
}
}
typedef SearchMangaRef = AutoDisposeFutureProviderRef<SearchMangaModel>;
/// See also [searchManga].
@ProviderFor(searchManga)
const searchMangaProvider = SearchMangaFamily();
/// See also [searchManga].
class SearchMangaFamily extends Family<AsyncValue<SearchMangaModel>> {
/// See also [searchManga].
const SearchMangaFamily();
/// See also [searchManga].
SearchMangaProvider call({
required String source,
required String query,
}) {
return SearchMangaProvider(
source: source,
query: query,
);
}
@override
SearchMangaProvider getProviderOverride(
covariant SearchMangaProvider provider,
) {
return call(
source: provider.source,
query: provider.query,
);
}
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'searchMangaProvider';
}
/// See also [searchManga].
class SearchMangaProvider extends AutoDisposeFutureProvider<SearchMangaModel> {
/// See also [searchManga].
SearchMangaProvider({
required this.source,
required this.query,
}) : super.internal(
(ref) => searchManga(
ref,
source: source,
query: query,
),
from: searchMangaProvider,
name: r'searchMangaProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$searchMangaHash,
dependencies: SearchMangaFamily._dependencies,
allTransitiveDependencies:
SearchMangaFamily._allTransitiveDependencies,
);
final String source;
final String query;
@override
bool operator ==(Object other) {
return other is SearchMangaProvider &&
other.source == source &&
other.query == query;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, source.hashCode);
hash = _SystemHash.combine(hash, query.hashCode);
return _SystemHash.finish(hash);
}
}
// 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

View file

@ -378,4 +378,53 @@ List<SourceModel> sourcesList = [
typeSource: TypeSource.mangathemesia,
logoUrl:
'https://xcalibrscans.com/wp-content/uploads/2021/06/xcalibr-dark-v3.png'),
SourceModel(
sourceName: "Fallen Angels",
url: "https://manga.fascans.com",
lang: "en",
typeSource: TypeSource.mmrcms,
logoUrl: ''),
SourceModel(
sourceName: "Scan FR",
url: "https://www.scan-fr.org",
lang: "fr",
typeSource: TypeSource.mmrcms,
logoUrl: ''),
SourceModel(
sourceName: "Scan VF",
url: "https://www.scan-vf.net",
lang: "fr",
typeSource: TypeSource.mmrcms,
logoUrl: ''), //
SourceModel(
sourceName: "Komikid",
url: "https://www.komikid.com",
lang: "id",
typeSource: TypeSource.mmrcms,
logoUrl: ''),
SourceModel(
sourceName: "MangaHanta",
url: "http://mangahanta.com",
lang: "tr",
typeSource: TypeSource.mmrcms,
logoUrl: ''),
SourceModel(
sourceName: "MangaID",
url: "https://mangaid.click",
lang: "id",
typeSource: TypeSource.mmrcms,
logoUrl: ''),
SourceModel(
sourceName: "Jpmangas",
url: "https://jpmangas.cc",
lang: "fr",
typeSource: TypeSource.mmrcms,
logoUrl: ''),
SourceModel(
sourceName: "FR Scan",
url: "https://frscan.ws",
lang: "fr",
typeSource: TypeSource.mmrcms,
logoUrl: ''),
];

View file

@ -41,7 +41,9 @@ enum TypeSource {
@HiveField(2)
mangathemesia,
@HiveField(3)
comick
comick,
@HiveField(4)
mmrcms
}
// @HiveType(typeId: 3)

View file

@ -77,6 +77,8 @@ class TypeSourceAdapter extends TypeAdapter<TypeSource> {
return TypeSource.mangathemesia;
case 3:
return TypeSource.comick;
case 4:
return TypeSource.mmrcms;
default:
return TypeSource.single;
}
@ -94,6 +96,9 @@ class TypeSourceAdapter extends TypeAdapter<TypeSource> {
case TypeSource.comick:
writer.writeByte(3);
break;
case TypeSource.mmrcms:
writer.writeByte(4);
break;
}
}

22
lib/utils/headers.dart Normal file
View file

@ -0,0 +1,22 @@
Map<String, String>? headers(String source) {
return source == 'japscan'
? {
'referer': 'https://www.japscan.lol/',
}
: source == 'mangakawaii'
? {
'Referer': 'https://www.mangakawaii.io/',
'User-Agent':
'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',
'Accept-Language': 'fr'
}
: source == 'mangahere'
? {"Referer": "https://www.mangahere.cc/", "Cookie": "isAdult=1"}
: source == 'comick'
? {
'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'
}
: {};
}

View file

@ -63,6 +63,7 @@ class _BrowseScreenState extends State<BrowseScreen>
_isSearch = false;
});
_textEditingController.clear();
entriesFilter = entries;
},
controller: _textEditingController,
)

View file

@ -55,6 +55,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
setState(() {
isSearch = false;
});
_textEditingController.clear();
},
controller: _textEditingController,
)

View file

@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/manga_type.dart';
import 'package:mangayomi/services/get_manga_detail.dart';
import 'package:mangayomi/services/get_popular_manga.dart';
import 'package:mangayomi/views/manga/home/manga_search_screen.dart';
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
import 'package:mangayomi/views/widgets/cover_view_widget.dart';
import 'package:mangayomi/views/widgets/gridview_widget.dart';
@ -29,7 +30,10 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
return Scaffold(
appBar: AppBar(
title: Text('${widget.mangaType.source}'),
actions: [],
actions: [
MangaSearchButton(
source: widget.mangaType.source!, lang: widget.mangaType.lang!)
],
),
body: getManga.when(
data: (data) {

View file

@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/services/search_manga.dart';
import 'package:mangayomi/views/manga/home/mang_home_screen.dart';
import 'package:mangayomi/views/widgets/gridview_widget.dart';
class MangaSearchButton extends StatelessWidget {
final String source;
final String lang;
MangaSearchButton({super.key, required this.source, required this.lang});
late final CustomSearchDelegate _delegate =
CustomSearchDelegate(source, lang);
@override
Widget build(BuildContext context) {
return IconButton(
icon: const Icon(Icons.search),
onPressed: () async {
await showSearch<dynamic>(
context: context,
delegate: _delegate,
);
},
);
}
}
class CustomSearchDelegate extends SearchDelegate {
final String source;
final String lang;
CustomSearchDelegate(this.source, this.lang);
@override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: const BackButtonIcon(),
onPressed: () {
Navigator.pop(context);
},
);
}
@override
Widget buildSuggestions(BuildContext context) {
return Container();
}
@override
Widget buildResults(BuildContext context) {
if (query.isEmpty) {
return const Center(child: Text("Empty"));
}
return SearchResult(
query: query,
source: source,
lang: lang,
);
}
@override
List<Widget>? buildActions(BuildContext context) {
if (query.isNotEmpty) {
return [
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}
return [];
}
@override
ThemeData appBarTheme(BuildContext context) {
final ThemeData theme = Theme.of(context);
return theme.copyWith(
appBarTheme: const AppBarTheme(),
inputDecorationTheme: const InputDecorationTheme(hintStyle: TextStyle()),
textTheme: theme.textTheme
.copyWith(titleLarge: theme.textTheme.titleLarge!.copyWith()),
);
}
}
class SearchResult extends ConsumerWidget {
final String query;
final String source;
final String lang;
const SearchResult({
super.key,
required this.query,
required this.source,
required this.lang,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final search = ref.watch(searchMangaProvider(source: source, query: query));
return search.when(
loading: () => const Center(
child: CircularProgressIndicator(),
),
error: (error, stackTrace) => const Center(child: Text("Error")),
data: (data) {
if (data.name.isNotEmpty) {
return GridViewWidget(
itemCount: data.name.length,
itemBuilder: (context, index) {
return MangaHomeImageCard(
url: data.url[index]!,
name: data.name[index]!,
image: data.image[index]!,
source: source,
lang: lang,
);
},
);
}
return const Center(
child: Text("Empty"),
);
});
}
}

View file

@ -1,6 +1,7 @@
import 'dart:io';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:mangayomi/utils/headers.dart';
class ImageViewHorizontal extends StatefulWidget {
final int length;
@ -43,10 +44,7 @@ class _ImageViewHorizontalState extends State<ImageViewHorizontal> {
clearMemoryCacheWhenDispose: true,
enableMemoryCache: false,
cacheMaxAge: const Duration(days: 7),
headers: const {
"Referer": "https://www.mangahere.cc/",
"Cookie": "isAdult=1"
},
headers: headers(widget.source),
mode: ExtendedImageMode.gesture,
initGestureConfigHandler: widget.initGestureConfigHandler,
onDoubleTap: widget.onDoubleTap,

View file

@ -3,6 +3,7 @@ import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:mangayomi/utils/headers.dart';
import 'package:mangayomi/utils/media_query.dart';
class ImageViewVertical extends ConsumerStatefulWidget {
@ -44,10 +45,7 @@ class _ImageViewVerticalState extends ConsumerState<ImageViewVertical>
height: MediaQuery.of(context).padding.top,
),
ExtendedImage.network(widget.url,
headers: const {
"Referer": "https://www.mangahere.cc/",
"Cookie": "isAdult=1"
},
headers: headers(widget.source),
handleLoadingProgress: true,
fit: BoxFit.contain,
cacheMaxAge: const Duration(days: 7),

View file

@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
import 'package:mangayomi/models/model_manga.dart';
import 'package:mangayomi/services/get_manga_detail.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/headers.dart';
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
import 'package:mangayomi/views/widgets/cover_view_widget.dart';
@ -50,10 +51,7 @@ class _MangaImageCardWidgetState extends ConsumerState<MangaImageCardWidget> {
},
child: CoverViewWidget(children: [
cachedNetworkImage(
headers: {
"Referer": "https://www.mangahere.cc/",
"Cookie": "isAdult=1"
},
headers: headers(widget.getMangaDetailModel!.source!),
imageUrl: widget.getMangaDetailModel!.imageUrl!,
width: 200,
height: 270,