refresh & search impl
This commit is contained in:
parent
8a2dba2e0d
commit
065f930472
15 changed files with 308 additions and 253 deletions
|
|
@ -1,5 +1,6 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.kodjodevf.mangayomi">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application
|
||||
android:label="mangayomi"
|
||||
android:name="${applicationName}"
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
"Referer": "https://www.mangahere.cc/",
|
||||
"Cookie": "isAdult=1"
|
||||
});
|
||||
log("message");
|
||||
var link = "http://www.mangahere.cc${modelManga.chapterUrl![index]}";
|
||||
dom.Document htmll = dom.Document.html(response.body);
|
||||
int? pagesNumber = -1;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'get_manga_chapter_url.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getMangaChapterUrlHash() =>
|
||||
r'bd696a5ff424b0396cd67d08325945f6ac00093b';
|
||||
r'38cf836814df00df1a3a269c0c2fc0c85debff78';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ lang(String lang) {
|
|||
return 'tr';
|
||||
} else if (lang == 'Polski') {
|
||||
return 'pl';
|
||||
} else if (lang == '中文') {
|
||||
} else if (lang == '中文(Zhōngwén)') {
|
||||
return 'zh';
|
||||
} else if (lang == '(Hong Kong) 繁體中文') {
|
||||
} else if (lang == '繁體中文(Hong Kong)') {
|
||||
return 'zh-hk';
|
||||
}
|
||||
}
|
||||
|
|
@ -68,9 +68,9 @@ completeLang(String lang) {
|
|||
} else if (lang == 'pl') {
|
||||
return 'Polski';
|
||||
} else if (lang == 'zh') {
|
||||
return '中文';
|
||||
return '中文(Zhōngwén)';
|
||||
} else if (lang == 'zh-hk') {
|
||||
return '(Hong Kong) 繁體中文';
|
||||
return '繁體中文(Hong Kong)';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +90,6 @@ final List<String> language = [
|
|||
'Polski',
|
||||
'Türkçe',
|
||||
'Deutsch',
|
||||
'中文',
|
||||
'(Hong Kong) 繁體中文'
|
||||
'中文(Zhōngwén)',
|
||||
'繁體中文(Hong Kong)'
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/views/browse/extension/extension_screen.dart';
|
||||
import 'package:mangayomi/views/browse/migrate_screen.dart';
|
||||
import 'package:mangayomi/views/browse/sources_screen.dart';
|
||||
import 'package:mangayomi/views/library/search_text_form_field.dart';
|
||||
|
||||
class BrowseScreen extends StatefulWidget {
|
||||
const BrowseScreen({super.key});
|
||||
|
|
@ -25,6 +29,10 @@ class _BrowseScreenState extends State<BrowseScreen>
|
|||
super.initState();
|
||||
}
|
||||
|
||||
List<SourceModel> entries = [];
|
||||
List<SourceModel> entriesFilter = [];
|
||||
final _textEditingController = TextEditingController();
|
||||
bool _isSearch = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTabController(
|
||||
|
|
@ -39,15 +47,40 @@ class _BrowseScreenState extends State<BrowseScreen>
|
|||
style: TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
actions: [
|
||||
if (_tabBarController.index != 2)
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {},
|
||||
icon: Icon(
|
||||
_tabBarController.index == 0
|
||||
? Icons.travel_explore_rounded
|
||||
: Icons.search_rounded,
|
||||
color: Theme.of(context).hintColor)),
|
||||
_isSearch
|
||||
? SeachFormTextField(
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
entriesFilter = entries
|
||||
.where((element) => element.sourceName
|
||||
.toLowerCase()
|
||||
.contains(value.toLowerCase()))
|
||||
.toList();
|
||||
});
|
||||
},
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isSearch = false;
|
||||
});
|
||||
},
|
||||
controller: _textEditingController,
|
||||
)
|
||||
: _tabBarController.index != 2
|
||||
? IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
if (_tabBarController.index == 1) {
|
||||
setState(() {
|
||||
_isSearch = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
_tabBarController.index == 0
|
||||
? Icons.travel_explore_rounded
|
||||
: Icons.search_rounded,
|
||||
color: Theme.of(context).hintColor))
|
||||
: Container(),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
|
|
@ -74,10 +107,15 @@ class _BrowseScreenState extends State<BrowseScreen>
|
|||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(controller: _tabBarController, children: const [
|
||||
SourcesScreen(),
|
||||
ExtensionScreen(),
|
||||
MigrateScreen()
|
||||
body: TabBarView(controller: _tabBarController, children: [
|
||||
const SourcesScreen(),
|
||||
ExtensionScreen(
|
||||
entriesData: (val) {
|
||||
entries = val as List<SourceModel>;
|
||||
},
|
||||
entriesFilter: entriesFilter,
|
||||
),
|
||||
const MigrateScreen()
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class ExtensionsLang extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
language.sort((a, b) => a.compareTo(b));
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Extensions"),
|
||||
|
|
|
|||
|
|
@ -8,76 +8,64 @@ import 'package:mangayomi/utils/lang.dart';
|
|||
import 'package:mangayomi/views/browse/extension/refresh_filter_data.dart';
|
||||
import 'package:mangayomi/views/browse/extension/widgets/extension_list_tile_widget.dart';
|
||||
|
||||
|
||||
class ExtensionScreen extends ConsumerWidget {
|
||||
const ExtensionScreen({super.key});
|
||||
final Function(dynamic) entriesData;
|
||||
final List<SourceModel> entriesFilter;
|
||||
const ExtensionScreen(
|
||||
{required this.entriesData, required this.entriesFilter, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final refreshFilter = ref.watch(refreshFilterDataProvider);
|
||||
|
||||
return refreshFilter.when(
|
||||
data: (data) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: ValueListenableBuilder<Box<SourceModel>>(
|
||||
valueListenable:
|
||||
ref.watch(hiveBoxMangaSourceProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values.toList();
|
||||
return GroupedListView<SourceModel, String>(
|
||||
elements: entries,
|
||||
groupBy: (element) =>
|
||||
completeLang(element.lang.toLowerCase()),
|
||||
groupSeparatorBuilder: (String groupByValue) => Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
groupByValue,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w300, fontSize: 12),
|
||||
),
|
||||
],
|
||||
ref.watch(refreshFilterDataProvider);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: ValueListenableBuilder<Box<SourceModel>>(
|
||||
valueListenable: ref.watch(hiveBoxMangaSourceProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values.toList();
|
||||
entriesData(entries);
|
||||
return GroupedListView<SourceModel, String>(
|
||||
elements: entriesFilter.isNotEmpty ? entriesFilter : entries,
|
||||
groupBy: (element) => completeLang(element.lang.toLowerCase()),
|
||||
groupSeparatorBuilder: (String groupByValue) => Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
groupByValue,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w300, fontSize: 12),
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, SourceModel element) {
|
||||
final source =
|
||||
value.get("${element.sourceName}${element.lang}")!;
|
||||
return ExtensionListTileWidget(
|
||||
lang: value
|
||||
.get("${element.sourceName}${element.lang}")!
|
||||
.lang,
|
||||
onChanged: (val) {
|
||||
value.put(
|
||||
"${element.sourceName}${element.lang}",
|
||||
SourceModel(
|
||||
sourceName: element.sourceName,
|
||||
url: element.url,
|
||||
lang: element.lang,
|
||||
typeSource: element.typeSource,
|
||||
isAdded: val,
|
||||
logoUrl: element.logoUrl));
|
||||
},
|
||||
sourceName: source.sourceName,
|
||||
value: source.isAdded,
|
||||
logoUrl: source.logoUrl,
|
||||
);
|
||||
],
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, SourceModel element) {
|
||||
final source =
|
||||
value.get("${element.sourceName}${element.lang}")!;
|
||||
return ExtensionListTileWidget(
|
||||
lang: value.get("${element.sourceName}${element.lang}")!.lang,
|
||||
onChanged: (val) {
|
||||
value.put(
|
||||
"${element.sourceName}${element.lang}",
|
||||
SourceModel(
|
||||
sourceName: element.sourceName,
|
||||
url: element.url,
|
||||
lang: element.lang,
|
||||
typeSource: element.typeSource,
|
||||
isAdded: val,
|
||||
logoUrl: element.logoUrl));
|
||||
},
|
||||
groupComparator: (group1, group2) => group1.compareTo(group2),
|
||||
itemComparator: (item1, item2) =>
|
||||
item1.sourceName.compareTo(item2.sourceName),
|
||||
order: GroupedListOrder.ASC,
|
||||
sourceName: source.sourceName,
|
||||
value: source.isAdded,
|
||||
logoUrl: source.logoUrl,
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) {
|
||||
return Container();
|
||||
},
|
||||
loading: () {
|
||||
return Container();
|
||||
},
|
||||
},
|
||||
groupComparator: (group1, group2) => group1.compareTo(group2),
|
||||
itemComparator: (item1, item2) =>
|
||||
item1.sourceName.compareTo(item2.sourceName),
|
||||
order: GroupedListOrder.ASC,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
part 'refresh_filter_data.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<bool> refreshFilterData(RefreshFilterDataRef ref) async {
|
||||
refreshFilterData(RefreshFilterDataRef ref) async {
|
||||
final lf = ref
|
||||
.watch(hiveBoxMangaFilterProvider)
|
||||
.get("language_filter", defaultValue: []);
|
||||
|
|
@ -69,5 +69,4 @@ Future<bool> refreshFilterData(RefreshFilterDataRef ref) async {
|
|||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ part of 'refresh_filter_data.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$refreshFilterDataHash() => r'0a4c4949efbe333131bef6b2e52ee94d81f06036';
|
||||
String _$refreshFilterDataHash() => r'78e543cb9e5bffa4a5960abeb9d7b2dd4cb23e30';
|
||||
|
||||
/// See also [refreshFilterData].
|
||||
@ProviderFor(refreshFilterData)
|
||||
final refreshFilterDataProvider = AutoDisposeFutureProvider<bool>.internal(
|
||||
final refreshFilterDataProvider = AutoDisposeProvider<dynamic>.internal(
|
||||
refreshFilterData,
|
||||
name: r'refreshFilterDataProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
|
|
@ -20,5 +20,5 @@ final refreshFilterDataProvider = AutoDisposeFutureProvider<bool>.internal(
|
|||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef RefreshFilterDataRef = AutoDisposeFutureProviderRef<bool>;
|
||||
typedef RefreshFilterDataRef = AutoDisposeProviderRef<dynamic>;
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -15,108 +15,96 @@ class SourcesScreen extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final refreshFilter = ref.watch(refreshFilterDataProvider);
|
||||
ref.watch(refreshFilterDataProvider);
|
||||
|
||||
return refreshFilter.when(
|
||||
data: (data) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: ValueListenableBuilder<Box<SourceModel>>(
|
||||
valueListenable:
|
||||
ref.watch(hiveBoxMangaSourceProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values
|
||||
.where((element) => element.isAdded == true)
|
||||
.toList();
|
||||
if (entries.isEmpty) {
|
||||
return const Center(child: Text("Empty"));
|
||||
}
|
||||
return GroupedListView<SourceModel, String>(
|
||||
elements: entries,
|
||||
groupBy: (element) =>
|
||||
completeLang(element.lang.toLowerCase()),
|
||||
groupSeparatorBuilder: (String groupByValue) => Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
groupByValue,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w300, fontSize: 12),
|
||||
),
|
||||
],
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: ValueListenableBuilder<Box<SourceModel>>(
|
||||
valueListenable: ref.watch(hiveBoxMangaSourceProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values
|
||||
.where((element) => element.isAdded == true)
|
||||
.toList();
|
||||
if (entries.isEmpty) {
|
||||
return const Center(child: Text("Empty"));
|
||||
}
|
||||
return GroupedListView<SourceModel, String>(
|
||||
elements: entries,
|
||||
groupBy: (element) => completeLang(element.lang.toLowerCase()),
|
||||
groupSeparatorBuilder: (String groupByValue) => Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
groupByValue,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w300, fontSize: 12),
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, SourceModel element) {
|
||||
final source =
|
||||
value.get("${element.sourceName}${element.lang}")!;
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
context.push('/mangaHome',
|
||||
extra: MangaType(
|
||||
isFullData: element.isFullData,
|
||||
lang: element.lang,
|
||||
source: element.sourceName));
|
||||
},
|
||||
leading: Container(
|
||||
height: 37,
|
||||
width: 37,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.secondaryHeaderColor
|
||||
.withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(5)),
|
||||
child: element.logoUrl.isEmpty
|
||||
? const Icon(Icons.source_outlined)
|
||||
: CachedNetworkImage(
|
||||
imageUrl: element.logoUrl,
|
||||
fit: BoxFit.contain,
|
||||
],
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, SourceModel element) {
|
||||
final source =
|
||||
value.get("${element.sourceName}${element.lang}")!;
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
context.push('/mangaHome',
|
||||
extra: MangaType(
|
||||
isFullData: element.isFullData,
|
||||
lang: element.lang,
|
||||
source: element.sourceName));
|
||||
},
|
||||
leading: Container(
|
||||
height: 37,
|
||||
width: 37,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.secondaryHeaderColor
|
||||
.withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(5)),
|
||||
child: element.logoUrl.isEmpty
|
||||
? const Icon(Icons.source_outlined)
|
||||
: CachedNetworkImage(
|
||||
imageUrl: element.logoUrl,
|
||||
fit: BoxFit.contain,
|
||||
width: 37,
|
||||
height: 37,
|
||||
errorWidget: (context, url, error) {
|
||||
return const SizedBox(
|
||||
width: 37,
|
||||
height: 37,
|
||||
errorWidget: (context, url, error) {
|
||||
return const SizedBox(
|
||||
width: 37,
|
||||
height: 37,
|
||||
child: Center(
|
||||
child: Icon(Icons.source_outlined),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
completeLang(source.lang.toLowerCase()),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w300, fontSize: 12),
|
||||
),
|
||||
title: Text(source.sourceName),
|
||||
trailing: SizedBox(
|
||||
width: 110,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: const [
|
||||
Icon(
|
||||
Icons.push_pin_outlined,
|
||||
color: Colors.black,
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
},
|
||||
groupComparator: (group1, group2) => group1.compareTo(group2),
|
||||
itemComparator: (item1, item2) =>
|
||||
item1.sourceName.compareTo(item2.sourceName),
|
||||
order: GroupedListOrder.ASC,
|
||||
child: Center(
|
||||
child: Icon(Icons.source_outlined),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
completeLang(source.lang.toLowerCase()),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w300, fontSize: 12),
|
||||
),
|
||||
title: Text(source.sourceName),
|
||||
trailing: SizedBox(
|
||||
width: 110,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: const [
|
||||
Icon(
|
||||
Icons.push_pin_outlined,
|
||||
color: Colors.black,
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) {
|
||||
return Container();
|
||||
},
|
||||
loading: () {
|
||||
return Container();
|
||||
},
|
||||
},
|
||||
groupComparator: (group1, group2) => group1.compareTo(group2),
|
||||
itemComparator: (item1, item2) =>
|
||||
item1.sourceName.compareTo(item2.sourceName),
|
||||
order: GroupedListOrder.ASC,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
|
@ -10,25 +12,60 @@ import 'package:mangayomi/models/model_manga.dart';
|
|||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
import 'package:mangayomi/views/library/search_text_form_field.dart';
|
||||
|
||||
class HistoryScreen extends ConsumerWidget {
|
||||
class HistoryScreen extends ConsumerStatefulWidget {
|
||||
const HistoryScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ConsumerState<HistoryScreen> createState() => _HistoryScreenState();
|
||||
}
|
||||
|
||||
class _HistoryScreenState extends ConsumerState<HistoryScreen> {
|
||||
final _textEditingController = TextEditingController();
|
||||
bool _isSearch = false;
|
||||
List<MangaHistoryModel> entriesData = [];
|
||||
List<MangaHistoryModel> entriesFilter = [];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
title: Text(
|
||||
'History',
|
||||
style: TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
title: _isSearch
|
||||
? null
|
||||
: Text(
|
||||
'History',
|
||||
style: TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {},
|
||||
icon: Icon(Icons.search, color: Theme.of(context).hintColor)),
|
||||
_isSearch
|
||||
? SeachFormTextField(
|
||||
onChanged: (value) {
|
||||
log(value.toString());
|
||||
setState(() {
|
||||
entriesFilter = entriesData
|
||||
.where((element) => element.modelManga.name!
|
||||
.toLowerCase()
|
||||
.contains(value.toLowerCase()))
|
||||
.toList();
|
||||
});
|
||||
},
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isSearch = false;
|
||||
});
|
||||
},
|
||||
controller: _textEditingController,
|
||||
)
|
||||
: IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isSearch = true;
|
||||
});
|
||||
},
|
||||
icon: Icon(Icons.search, color: Theme.of(context).hintColor)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {},
|
||||
|
|
@ -42,9 +79,10 @@ class HistoryScreen extends ConsumerWidget {
|
|||
valueListenable: ref.watch(hiveBoxMangaHistory).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values.toList();
|
||||
entriesData = entries;
|
||||
if (entries.isNotEmpty) {
|
||||
return GroupedListView<MangaHistoryModel, String>(
|
||||
elements: entries,
|
||||
elements: entriesFilter.isNotEmpty ? entriesFilter : entries,
|
||||
groupBy: (element) => element.date.substring(0, 10),
|
||||
groupSeparatorBuilder: (String groupByValue) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:hive_flutter/hive_flutter.dart';
|
|||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/views/library/search_text_form_field.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';
|
||||
|
|
@ -35,41 +36,20 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen> {
|
|||
),
|
||||
actions: [
|
||||
isSearch
|
||||
? Flexible(
|
||||
child: TextFormField(
|
||||
style: const TextStyle(fontFamily: 'Lato'),
|
||||
controller: _textEditingController,
|
||||
keyboardType: TextInputType.text,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
entriesFilter = entries
|
||||
.where((element) =>
|
||||
element.name!.toLowerCase().contains(value))
|
||||
.toList();
|
||||
});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Seach...',
|
||||
filled: true,
|
||||
fillColor: Colors.transparent,
|
||||
prefixIcon: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isSearch = false;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back,
|
||||
)),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
border: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none)),
|
||||
),
|
||||
? SeachFormTextField(
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
entriesFilter = entries
|
||||
.where((element) =>
|
||||
element.name!.toLowerCase().contains(value))
|
||||
.toList();
|
||||
});
|
||||
},
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isSearch = false;
|
||||
});
|
||||
}, controller: _textEditingController,
|
||||
)
|
||||
: IconButton(
|
||||
splashRadius: 20,
|
||||
|
|
|
|||
41
lib/views/library/search_text_form_field.dart
Normal file
41
lib/views/library/search_text_form_field.dart
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class SeachFormTextField extends StatelessWidget {
|
||||
final Function(String)? onChanged;
|
||||
final VoidCallback onPressed;
|
||||
final TextEditingController controller;
|
||||
const SeachFormTextField(
|
||||
{super.key,
|
||||
required this.onChanged,
|
||||
required this.onPressed,
|
||||
required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Flexible(
|
||||
child: TextFormField(
|
||||
autofocus: true,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.text,
|
||||
onChanged: onChanged,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: 'Search...',
|
||||
filled: true,
|
||||
fillColor: Colors.transparent,
|
||||
prefixIcon: IconButton(
|
||||
onPressed: onPressed,
|
||||
icon: const Icon(
|
||||
Icons.arrow_back,
|
||||
)),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
border: const OutlineInputBorder(borderSide: BorderSide.none)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class SeachWi extends StatefulWidget {
|
||||
const SeachWi({super.key});
|
||||
|
||||
@override
|
||||
State<SeachWi> createState() => _SeachWiState();
|
||||
}
|
||||
|
||||
class _SeachWiState extends State<SeachWi> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PreferredSize(
|
||||
child: AppBar(
|
||||
title: Row(
|
||||
children: [],
|
||||
),
|
||||
),
|
||||
preferredSize: Size.fromHeight(AppBar().preferredSize.height));
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,9 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
),
|
||||
body: getManga.when(
|
||||
data: (data) {
|
||||
if (data.url.isEmpty) {
|
||||
return const Center(child: Text("No result"));
|
||||
}
|
||||
_scrollController.addListener(() {
|
||||
if (_scrollController.position.pixels ==
|
||||
_scrollController.position.maxScrollExtent) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue