global search feature
This commit is contained in:
parent
335fba457a
commit
8bba523ba6
26 changed files with 471 additions and 73 deletions
|
|
@ -6,11 +6,13 @@ import 'package:mangayomi/models/manga_type.dart';
|
|||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/views/browse/browse_screen.dart';
|
||||
import 'package:mangayomi/views/browse/extension/extension_lang.dart';
|
||||
import 'package:mangayomi/views/browse/global_search_screen.dart';
|
||||
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/manga_home_screen.dart';
|
||||
import 'package:mangayomi/views/manga/home/manga_search_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';
|
||||
|
|
@ -177,6 +179,44 @@ class AsyncRouterNotifier extends ChangeNotifier {
|
|||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: "/globalSearch",
|
||||
name: "globalSearch",
|
||||
builder: (context, state) {
|
||||
return const GlobalSearchScreen();
|
||||
},
|
||||
pageBuilder: (context, state) {
|
||||
return CustomTransition(
|
||||
key: state.pageKey,
|
||||
child: const GlobalSearchScreen(),
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: "/searchResult",
|
||||
name: "searchResult",
|
||||
builder: (context, state) {
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
return SearchResultScreen(
|
||||
query: data['query']!,
|
||||
lang: data['lang']!,
|
||||
source: data['source']!,
|
||||
viewOnly: data['viewOnly'],
|
||||
);
|
||||
},
|
||||
pageBuilder: (context, state) {
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
return CustomTransition(
|
||||
key: state.pageKey,
|
||||
child: SearchResultScreen(
|
||||
query: data['query']!,
|
||||
lang: data['lang']!,
|
||||
source: data['source']!,
|
||||
viewOnly: data['viewOnly'],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'get_manga_chapter_url.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getMangaChapterUrlHash() =>
|
||||
r'a9425fc3bdffdf9d8f50acdd7e58671d8ff41a6a';
|
||||
r'b17d3053901db005a4eee673163d2dc78ceb75f4';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ beautifyChapterName(String? vol, String? chap, String? title, String? lang) {
|
|||
Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String name,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
List<String> genre = [];
|
||||
|
|
@ -604,7 +604,7 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
genre: genre,
|
||||
author: author,
|
||||
description: description,
|
||||
name: name,
|
||||
name: title,
|
||||
url: url,
|
||||
source: source,
|
||||
imageUrl: imageUrl,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_manga_detail.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getMangaDetailHash() => r'9079556aadc0a4b027620d3c5b75280268c022f8';
|
||||
String _$getMangaDetailHash() => r'b312cc1f35a45520a827c87b7be862cf5f67ffb3';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -44,14 +44,14 @@ class GetMangaDetailFamily extends Family<AsyncValue<GetMangaDetailModel>> {
|
|||
GetMangaDetailProvider call({
|
||||
required String imageUrl,
|
||||
required String url,
|
||||
required String name,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source,
|
||||
}) {
|
||||
return GetMangaDetailProvider(
|
||||
imageUrl: imageUrl,
|
||||
url: url,
|
||||
name: name,
|
||||
title: title,
|
||||
lang: lang,
|
||||
source: source,
|
||||
);
|
||||
|
|
@ -64,7 +64,7 @@ class GetMangaDetailFamily extends Family<AsyncValue<GetMangaDetailModel>> {
|
|||
return call(
|
||||
imageUrl: provider.imageUrl,
|
||||
url: provider.url,
|
||||
name: provider.name,
|
||||
title: provider.title,
|
||||
lang: provider.lang,
|
||||
source: provider.source,
|
||||
);
|
||||
|
|
@ -92,7 +92,7 @@ class GetMangaDetailProvider
|
|||
GetMangaDetailProvider({
|
||||
required this.imageUrl,
|
||||
required this.url,
|
||||
required this.name,
|
||||
required this.title,
|
||||
required this.lang,
|
||||
required this.source,
|
||||
}) : super.internal(
|
||||
|
|
@ -100,7 +100,7 @@ class GetMangaDetailProvider
|
|||
ref,
|
||||
imageUrl: imageUrl,
|
||||
url: url,
|
||||
name: name,
|
||||
title: title,
|
||||
lang: lang,
|
||||
source: source,
|
||||
),
|
||||
|
|
@ -117,7 +117,7 @@ class GetMangaDetailProvider
|
|||
|
||||
final String imageUrl;
|
||||
final String url;
|
||||
final String name;
|
||||
final String title;
|
||||
final String lang;
|
||||
final String source;
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ class GetMangaDetailProvider
|
|||
return other is GetMangaDetailProvider &&
|
||||
other.imageUrl == imageUrl &&
|
||||
other.url == url &&
|
||||
other.name == name &&
|
||||
other.title == title &&
|
||||
other.lang == lang &&
|
||||
other.source == source;
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ class GetMangaDetailProvider
|
|||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, imageUrl.hashCode);
|
||||
hash = _SystemHash.combine(hash, url.hashCode);
|
||||
hash = _SystemHash.combine(hash, name.hashCode);
|
||||
hash = _SystemHash.combine(hash, title.hashCode);
|
||||
hash = _SystemHash.combine(hash, lang.hashCode);
|
||||
hash = _SystemHash.combine(hash, source.hashCode);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_popular_manga.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getPopularMangaHash() => r'57e376026390038dbcf96f93b7a2e25a188d3156';
|
||||
String _$getPopularMangaHash() => r'cc0567f4659ae10b5e55ccdbb5f5a9560cc09a16';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,59 @@ Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
|||
.toList();
|
||||
}
|
||||
}
|
||||
/***********/
|
||||
/*mangakawaii*/
|
||||
/***********/
|
||||
else if (source == "mangakawaii") {
|
||||
final dom = await httpResToDom(
|
||||
url:
|
||||
'https://www.mangakawaii.io/search?query=${query.trim()}&search_type=manga',
|
||||
headers: {'Accept-Language': 'fr'});
|
||||
|
||||
if (dom
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.isNotEmpty) {
|
||||
final ur = dom
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
for (var a in ur) {
|
||||
url.add(a!);
|
||||
}
|
||||
|
||||
final nam = dom
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
for (var a in nam) {
|
||||
name.add(a);
|
||||
image.add('');
|
||||
}
|
||||
}
|
||||
}
|
||||
/***********/
|
||||
/*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);
|
||||
for (var ok in rep['suggestions']) {
|
||||
if (source == 'Read Comics Online') {
|
||||
url.add('${getWpMangaUrl(source)}/comic/${ok['data']}');
|
||||
} else if (source == 'Scan VF') {
|
||||
url.add('${getWpMangaUrl(source)}/${ok['data']}');
|
||||
} else {
|
||||
url.add('${getWpMangaUrl(source)}/manga/${ok['data']}');
|
||||
}
|
||||
name.add(ok["value"]);
|
||||
image.add('');
|
||||
}
|
||||
}
|
||||
/***********/
|
||||
/*mangahere*/
|
||||
/***********/
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ class _BrowseScreenState extends State<BrowseScreen>
|
|||
.toList();
|
||||
});
|
||||
},
|
||||
onSuffixPressed: () {
|
||||
_textEditingController.clear();
|
||||
},
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isSearch = false;
|
||||
|
|
@ -76,6 +79,10 @@ class _BrowseScreenState extends State<BrowseScreen>
|
|||
setState(() {
|
||||
_isSearch = true;
|
||||
});
|
||||
} else if (_tabBarController.index == 0) {
|
||||
context.push(
|
||||
'/globalSearch',
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
|
|
|
|||
|
|
@ -73,6 +73,5 @@ class ExtensionsLang extends ConsumerWidget {
|
|||
);
|
||||
}),
|
||||
);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mangayomi/utils/lang.dart';
|
||||
|
|
@ -20,7 +18,6 @@ class ExtensionListTileWidget extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// log(logoUrl);
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
onChanged(!value);
|
||||
|
|
@ -59,6 +56,5 @@ class ExtensionListTileWidget extends StatelessWidget {
|
|||
onChanged: (value) {
|
||||
onChanged(value);
|
||||
}));
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
247
lib/views/browse/global_search_screen.dart
Normal file
247
lib/views/browse/global_search_screen.dart
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/services/get_manga_detail.dart';
|
||||
import 'package:mangayomi/services/search_manga.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/lang.dart';
|
||||
import 'package:mangayomi/views/library/search_text_form_field.dart';
|
||||
import 'package:mangayomi/views/manga/home/manga_home_screen.dart';
|
||||
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
|
||||
import 'package:mangayomi/views/widgets/manga_image_card_widget.dart';
|
||||
|
||||
class GlobalSearchScreen extends ConsumerStatefulWidget {
|
||||
const GlobalSearchScreen({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<GlobalSearchScreen> createState() => _GlobalSearchScreenState();
|
||||
}
|
||||
|
||||
class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
|
||||
String query = "";
|
||||
final _textEditingController = TextEditingController();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sourceList = ref
|
||||
.watch(hiveBoxMangaSourceProvider)
|
||||
.values
|
||||
.where((element) => element.isAdded == true)
|
||||
.toList();
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: Container(),
|
||||
actions: [
|
||||
SeachFormTextField(
|
||||
onChanged: (value) {},
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
onFieldSubmitted: (value) {
|
||||
setState(() {
|
||||
query = value;
|
||||
});
|
||||
},
|
||||
onSuffixPressed: () {
|
||||
_textEditingController.clear();
|
||||
setState(() {
|
||||
query = "";
|
||||
});
|
||||
},
|
||||
controller: _textEditingController,
|
||||
)
|
||||
],
|
||||
),
|
||||
body: query.isNotEmpty
|
||||
? ListView(
|
||||
children: [
|
||||
for (var i = 0; i < sourceList.length; i++)
|
||||
SizedBox(
|
||||
height: 230,
|
||||
child: SourceSearchScreen(
|
||||
query: query,
|
||||
source: sourceList[i],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Container(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SourceSearchScreen extends ConsumerWidget {
|
||||
final String query;
|
||||
|
||||
final SourceModel source;
|
||||
const SourceSearchScreen({
|
||||
super.key,
|
||||
required this.query,
|
||||
required this.source,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final search =
|
||||
ref.watch(searchMangaProvider(source: source.sourceName, query: query));
|
||||
return Scaffold(
|
||||
body: SizedBox(
|
||||
height: 240,
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
dense: true,
|
||||
onTap: () {
|
||||
Map<String, dynamic> data = {
|
||||
'query': query,
|
||||
'source': source.sourceName,
|
||||
'lang': source.lang,
|
||||
'viewOnly': true,
|
||||
};
|
||||
context.push('/searchResult', extra: data);
|
||||
},
|
||||
title: Text(source.sourceName),
|
||||
subtitle: Text(
|
||||
completeLang(source.lang),
|
||||
style: const TextStyle(fontSize: 10),
|
||||
),
|
||||
trailing: const Icon(Icons.arrow_forward_sharp),
|
||||
),
|
||||
Flexible(
|
||||
child: search.when(
|
||||
loading: () => const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
error: (error, stackTrace) =>
|
||||
Center(child: Text(error.toString())),
|
||||
data: (data) {
|
||||
if (data.name.isNotEmpty) {
|
||||
return ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: data.name.length,
|
||||
itemBuilder: (context, index) {
|
||||
return MangaGlobalImageCard(
|
||||
url: data.url[index]!,
|
||||
name: data.name[index]!,
|
||||
image: data.image[index]!,
|
||||
source: source.sourceName,
|
||||
lang: source.lang,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return const Center(
|
||||
child: Text("No result"),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class MangaGlobalImageCard extends ConsumerStatefulWidget {
|
||||
final String image;
|
||||
final String url;
|
||||
final String name;
|
||||
final String source;
|
||||
final String lang;
|
||||
const MangaGlobalImageCard({
|
||||
super.key,
|
||||
required this.url,
|
||||
required this.name,
|
||||
required this.image,
|
||||
required this.source,
|
||||
required this.lang,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<MangaGlobalImageCard> createState() =>
|
||||
_MangaGlobalImageCardState();
|
||||
}
|
||||
|
||||
class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
|
||||
with AutomaticKeepAliveClientMixin<MangaGlobalImageCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final getMangaDetail = ref.watch(getMangaDetailProvider(
|
||||
source: widget.source,
|
||||
imageUrl: widget.image,
|
||||
title: widget.name,
|
||||
url: widget.url,
|
||||
lang: widget.lang));
|
||||
|
||||
return getMangaDetail.when(
|
||||
data: (data) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
final modelManga = ModelManga(
|
||||
imageUrl: data.imageUrl,
|
||||
name: data.name,
|
||||
genre: data.genre,
|
||||
author: data.author,
|
||||
chapterDate: data.chapterDate,
|
||||
chapterTitle: data.chapterTitle,
|
||||
chapterUrl: data.chapterUrl,
|
||||
status: data.status,
|
||||
description: data.description,
|
||||
favorite: false,
|
||||
link: data.url,
|
||||
source: data.source,
|
||||
lang: widget.lang);
|
||||
if (mounted) {
|
||||
context.push('/manga-reader/detail', extra: modelManga);
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 90,
|
||||
child: Column(children: [
|
||||
cachedNetworkImage(
|
||||
headers: headers(data.source!),
|
||||
imageUrl: data.imageUrl!,
|
||||
width: 80,
|
||||
height: 120,
|
||||
fit: BoxFit.fill),
|
||||
BottomTextWidget(
|
||||
fontSize: 12.0,
|
||||
text: widget.name,
|
||||
isLoading: true,
|
||||
isComfortableGrid: true,
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
},
|
||||
loading: () => SizedBox(
|
||||
width: 60,
|
||||
child: Column(children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
child: Container(
|
||||
color: Theme.of(context).cardColor,
|
||||
width: 80,
|
||||
height: 120,
|
||||
),
|
||||
),
|
||||
BottomTextWidget(
|
||||
fontSize: 12.0,
|
||||
text: widget.name,
|
||||
isLoading: true,
|
||||
isComfortableGrid: true,
|
||||
)
|
||||
]),
|
||||
),
|
||||
error: (error, stackTrace) => Center(child: Text(error.toString())),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ class MigrateScreen extends StatefulWidget {
|
|||
class _MigrateScreenState extends State<MigrateScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
return const Center(
|
||||
child: Text('Migrate'),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
_isSearch
|
||||
? SeachFormTextField(
|
||||
onChanged: (value) {
|
||||
log(value.toString());
|
||||
setState(() {
|
||||
entriesFilter = entriesData
|
||||
.where((element) => element.modelManga.name!
|
||||
|
|
@ -51,6 +50,9 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
.toList();
|
||||
});
|
||||
},
|
||||
onSuffixPressed: () {
|
||||
_textEditingController.clear();
|
||||
},
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isSearch = false;
|
||||
|
|
@ -69,7 +71,40 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
icon: Icon(Icons.search, color: Theme.of(context).hintColor)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"Remove everything",
|
||||
),
|
||||
content: const Text(
|
||||
'Are you sure? All history will be lost.'),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text("Cancel")),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ref.watch(hiveBoxMangaHistory).clear();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text("Ok")),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: Icon(Icons.delete_sweep_outlined,
|
||||
color: Theme.of(context).hintColor)),
|
||||
],
|
||||
|
|
@ -80,6 +115,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
valueListenable: ref.watch(hiveBoxMangaHistory).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values.toList();
|
||||
entriesData = value.values.toList();
|
||||
final entriesHistory = _textEditingController.text.isNotEmpty
|
||||
? entriesFilter
|
||||
: entries;
|
||||
|
|
@ -212,13 +248,14 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"Delete",
|
||||
"Remove",
|
||||
),
|
||||
content: const Text(
|
||||
'This will remove the read date of this chapter. Are you sure?'),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceAround,
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
|
|
@ -226,7 +263,10 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
context);
|
||||
},
|
||||
child: const Text(
|
||||
"No")),
|
||||
"Cancel")),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
|
|
@ -239,7 +279,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
context);
|
||||
},
|
||||
child: const Text(
|
||||
"Yes")),
|
||||
"Remove")),
|
||||
],
|
||||
)
|
||||
],
|
||||
|
|
@ -266,7 +306,9 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
|||
order: GroupedListOrder.DESC,
|
||||
);
|
||||
}
|
||||
return const Center(child: Text(""));
|
||||
return const Center(
|
||||
child: Text('Nothing read recently'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
_textEditingController.clear();
|
||||
},
|
||||
controller: _textEditingController,
|
||||
onSuffixPressed: () {
|
||||
_textEditingController.clear();
|
||||
},
|
||||
)
|
||||
: IconButton(
|
||||
splashRadius: 20,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ final libraryReverseListStateProvider =
|
|||
|
||||
typedef _$LibraryReverseListState = AutoDisposeNotifier<bool>;
|
||||
String _$libraryDisplayTypeStateHash() =>
|
||||
r'e3c78daf9932930aa9df05a2718d087089744522';
|
||||
r'2743481e54668fe95294194b62014f9713de2cb8';
|
||||
|
||||
/// See also [LibraryDisplayTypeState].
|
||||
@ProviderFor(LibraryDisplayTypeState)
|
||||
|
|
|
|||
|
|
@ -3,12 +3,16 @@ import 'package:flutter/material.dart';
|
|||
class SeachFormTextField extends StatelessWidget {
|
||||
final Function(String)? onChanged;
|
||||
final VoidCallback onPressed;
|
||||
final VoidCallback onSuffixPressed;
|
||||
final TextEditingController controller;
|
||||
final Function(String)? onFieldSubmitted;
|
||||
const SeachFormTextField(
|
||||
{super.key,
|
||||
required this.onChanged,
|
||||
required this.onPressed,
|
||||
required this.controller});
|
||||
required this.controller,
|
||||
this.onFieldSubmitted,
|
||||
required this.onSuffixPressed});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -18,6 +22,7 @@ class SeachFormTextField extends StatelessWidget {
|
|||
controller: controller,
|
||||
keyboardType: TextInputType.text,
|
||||
onChanged: onChanged,
|
||||
onFieldSubmitted: onFieldSubmitted,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: 'Search...',
|
||||
|
|
@ -28,6 +33,8 @@ class SeachFormTextField extends StatelessWidget {
|
|||
icon: const Icon(
|
||||
Icons.arrow_back,
|
||||
)),
|
||||
suffixIcon: IconButton(
|
||||
onPressed: onSuffixPressed, icon: const Icon(Icons.clear)),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -85,6 +85,5 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
);
|
||||
},
|
||||
);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,5 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
);
|
||||
},
|
||||
);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
|
|||
.watch(getMangaDetailProvider(
|
||||
imageUrl: '',
|
||||
lang: widget.modelManga.lang!,
|
||||
name: widget.modelManga.name!,
|
||||
title: widget.modelManga.name!,
|
||||
source: widget.modelManga.source!,
|
||||
url: widget.modelManga.link!)
|
||||
.future)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
|
|||
final getMangaDetail = ref.watch(getMangaDetailProvider(
|
||||
source: widget.source,
|
||||
imageUrl: widget.image,
|
||||
name: widget.name,
|
||||
title: widget.name,
|
||||
url: widget.url,
|
||||
lang: widget.lang));
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class CustomSearchDelegate extends SearchDelegate {
|
|||
return const Center(child: Text("Empty"));
|
||||
}
|
||||
|
||||
return SearchResult(
|
||||
return SearchResultScreen(
|
||||
query: query,
|
||||
source: source,
|
||||
lang: lang,
|
||||
|
|
@ -86,43 +86,51 @@ class CustomSearchDelegate extends SearchDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
class SearchResult extends ConsumerWidget {
|
||||
class SearchResultScreen extends ConsumerWidget {
|
||||
final String query;
|
||||
final String source;
|
||||
final String lang;
|
||||
const SearchResult({
|
||||
final bool viewOnly;
|
||||
const SearchResultScreen({
|
||||
super.key,
|
||||
required this.query,
|
||||
required this.source,
|
||||
required this.lang,
|
||||
this.viewOnly = false,
|
||||
});
|
||||
|
||||
@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) => Center(child: Text(error.toString())),
|
||||
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 Scaffold(
|
||||
appBar: viewOnly
|
||||
? AppBar(
|
||||
title: Text(query),
|
||||
)
|
||||
: null,
|
||||
body: search.when(
|
||||
loading: () => const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
error: (error, stackTrace) => Center(child: Text(error.toString())),
|
||||
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"),
|
||||
);
|
||||
});
|
||||
}
|
||||
return const Center(
|
||||
child: Text("Empty"),
|
||||
);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class CurrentIndexProvider
|
|||
}
|
||||
}
|
||||
|
||||
String _$readerControllerHash() => r'a2acca315e2e89858de09af86f749a3a9ee2a9b9';
|
||||
String _$readerControllerHash() => r'8d9f171beadfd98a701e370a4f9a8e145d6b31de';
|
||||
|
||||
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
|
||||
late final MangaReaderModel mangaReaderModel;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ class UpdatesScreen extends StatelessWidget {
|
|||
icon: Icon(Icons.refresh, color: Theme.of(context).hintColor)),
|
||||
],
|
||||
),
|
||||
body: const Center(
|
||||
child: Text("No recent updates"),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ class BottomTextWidget extends StatelessWidget {
|
|||
final bool isLoading;
|
||||
final String text;
|
||||
final bool isComfortableGrid;
|
||||
final double? fontSize;
|
||||
const BottomTextWidget(
|
||||
{super.key,
|
||||
required this.text,
|
||||
this.isLoading = false,
|
||||
this.isComfortableGrid = false});
|
||||
this.isComfortableGrid = false,
|
||||
this.fontSize = 13.0});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -20,10 +22,10 @@ class BottomTextWidget extends StatelessWidget {
|
|||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
fontSize: 13.0,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
shadows: const [
|
||||
Shadow(offset: Offset(0.5, 0.9), blurRadius: 3.0)
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -241,14 +241,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
draggable_menu:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: draggable_menu
|
||||
sha256: "534e9fd85c9e37849456a8359561a6814f2b8048e04be7d97d3cdc76224ff33d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
draggable_scrollbar:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ dependencies:
|
|||
intl: ^0.18.0
|
||||
# rive: ^0.10.3
|
||||
google_fonts: ^4.0.3
|
||||
draggable_menu: ^0.2.0
|
||||
# draggable_menu: ^0.2.0
|
||||
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
|
|
|
|||
Loading…
Reference in a new issue