manga library diplay type, category **
This commit is contained in:
parent
48b4c6b229
commit
088514dc17
28 changed files with 1428 additions and 274 deletions
|
|
@ -8,8 +8,8 @@ class CategoriesModel extends HiveObject {
|
|||
final int id;
|
||||
@HiveField(1)
|
||||
final String name;
|
||||
@HiveField(2)
|
||||
final List<ModelManga> listModelManga;
|
||||
CategoriesModel(
|
||||
{required this.id, required this.name, required this.listModelManga});
|
||||
CategoriesModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,20 +19,17 @@ class CategoriesModelAdapter extends TypeAdapter<CategoriesModel> {
|
|||
return CategoriesModel(
|
||||
id: fields[0] as int,
|
||||
name: fields[1] as String,
|
||||
listModelManga: (fields[2] as List).cast<ModelManga>(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, CategoriesModel obj) {
|
||||
writer
|
||||
..writeByte(3)
|
||||
..writeByte(2)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
..write(obj.name)
|
||||
..writeByte(2)
|
||||
..write(obj.listModelManga);
|
||||
..write(obj.name);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class ModelManga extends HiveObject {
|
|||
String? lastRead;
|
||||
|
||||
@HiveField(14)
|
||||
int? category;
|
||||
List<int>? categories;
|
||||
|
||||
ModelManga(
|
||||
{required this.source,
|
||||
|
|
@ -62,7 +62,7 @@ class ModelManga extends HiveObject {
|
|||
required this.description,
|
||||
required this.dateAdded,
|
||||
required this.lastUpdate,
|
||||
required this.category,
|
||||
required this.categories,
|
||||
required this.lastRead,
|
||||
required this.chapters});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class ModelMangaAdapter extends TypeAdapter<ModelManga> {
|
|||
description: fields[3] as String?,
|
||||
dateAdded: fields[10] as int?,
|
||||
lastUpdate: fields[11] as int?,
|
||||
category: fields[14] as int?,
|
||||
categories: (fields[14] as List?)?.cast<int>(),
|
||||
lastRead: fields[13] as String?,
|
||||
chapters: (fields[12] as List?)?.cast<ModelChapters>(),
|
||||
);
|
||||
|
|
@ -68,7 +68,7 @@ class ModelMangaAdapter extends TypeAdapter<ModelManga> {
|
|||
..writeByte(13)
|
||||
..write(obj.lastRead)
|
||||
..writeByte(14)
|
||||
..write(obj.category);
|
||||
..write(obj.categories);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'get_manga_chapter_url.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getMangaChapterUrlHash() =>
|
||||
r'7645294b8966c7069d9c2e4528e1fee512bb1694';
|
||||
r'af6919ddfaafdafc0e8c2fa0fa0f686dfccd934a';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
|
|||
dateAdded: DateTime.now().microsecondsSinceEpoch,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: data.chapters,
|
||||
category: null,
|
||||
categories: null,
|
||||
lastRead: '');
|
||||
if (mounted) {
|
||||
context.push('/manga-reader/detail', extra: modelManga);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:draggable_menu/draggable_menu.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/categories.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
|
|
@ -24,124 +27,182 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
List<ModelManga> entries = [];
|
||||
List<ModelManga> entriesFilter = [];
|
||||
final _textEditingController = TextEditingController();
|
||||
|
||||
late TabController tabBarController;
|
||||
int tabIndex = 0;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final reverse = ref.watch(libraryReverseListStateProvider);
|
||||
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider);
|
||||
final continueReaderBtn =
|
||||
ref.watch(libraryShowContinueReadingButtonStateProvider);
|
||||
final showNumbersOfItems =
|
||||
ref.watch(libraryShowNumbersOfItemsStateProvider);
|
||||
final downloadedChapter = ref.watch(libraryDownloadedChaptersStateProvider);
|
||||
final language = ref.watch(libraryLanguageStateProvider);
|
||||
final displayType = ref
|
||||
.read(libraryDisplayTypeStateProvider.notifier)
|
||||
.getLibraryDisplayTypeValue(ref.watch(libraryDisplayTypeStateProvider));
|
||||
final isNotFiltering = ref
|
||||
.read(mangaFilterResultStateProvider(mangaList: entries).notifier)
|
||||
.isNotFiltering();
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
title: isSearch
|
||||
? null
|
||||
: Text(
|
||||
'Library',
|
||||
style: TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
actions: [
|
||||
isSearch
|
||||
? SeachFormTextField(
|
||||
onChanged: (value) {
|
||||
setState(() {});
|
||||
},
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isSearch = false;
|
||||
});
|
||||
_textEditingController.clear();
|
||||
},
|
||||
controller: _textEditingController,
|
||||
onSuffixPressed: () {
|
||||
_textEditingController.clear();
|
||||
setState(() {});
|
||||
},
|
||||
)
|
||||
: IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isSearch = true;
|
||||
});
|
||||
_textEditingController.clear();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.search,
|
||||
)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
_showDraggableMenu();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.filter_list_sharp,
|
||||
color: isNotFiltering ? null : Colors.yellow,
|
||||
)),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Open random entry")),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {}),
|
||||
],
|
||||
),
|
||||
body: ValueListenableBuilder<Box<ModelManga>>(
|
||||
valueListenable: ref.watch(hiveBoxMangaProvider).listenable(),
|
||||
return ValueListenableBuilder<Box<CategoriesModel>>(
|
||||
valueListenable: ref.watch(hiveBoxCategoriesProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
entries = value.values.where((element) => element.favorite).toList();
|
||||
final data =
|
||||
ref.watch(mangaFilterResultStateProvider(mangaList: entries));
|
||||
entriesFilter = _textEditingController.text.isNotEmpty
|
||||
? data
|
||||
.where((element) => element.name!
|
||||
.toLowerCase()
|
||||
.contains(_textEditingController.text.toLowerCase()))
|
||||
.toList()
|
||||
: data;
|
||||
final entriesManga =
|
||||
reverse ? entriesFilter.reversed.toList() : entriesFilter;
|
||||
final entr = value.values.toList();
|
||||
if (entr.isNotEmpty && showCategoryTabs) {
|
||||
tabBarController = TabController(length: entr.length, vsync: this);
|
||||
tabBarController.animateTo(tabIndex);
|
||||
tabBarController.addListener(() {
|
||||
tabIndex = tabBarController.index;
|
||||
});
|
||||
return DefaultTabController(
|
||||
length: entr.length,
|
||||
child: Scaffold(
|
||||
appBar:
|
||||
_appBar(isNotFiltering, showNumbersOfItems, entries.length),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TabBar(
|
||||
isScrollable: true,
|
||||
controller: tabBarController,
|
||||
tabs: entr.map((e) => Tab(text: e.name)).toList()),
|
||||
Flexible(
|
||||
child: TabBarView(
|
||||
controller: tabBarController,
|
||||
children: entr
|
||||
.map(
|
||||
(e) => Scaffold(
|
||||
body: ValueListenableBuilder<Box<ModelManga>>(
|
||||
valueListenable: ref
|
||||
.watch(hiveBoxMangaProvider)
|
||||
.listenable(),
|
||||
builder: (context, value, child) {
|
||||
entries = value.values
|
||||
.where((element) =>
|
||||
element.favorite &&
|
||||
element.categories != null &&
|
||||
element.categories!.contains(e.id))
|
||||
.toList();
|
||||
final data = ref.watch(
|
||||
mangaFilterResultStateProvider(
|
||||
mangaList: entries));
|
||||
entriesFilter = _textEditingController
|
||||
.text.isNotEmpty
|
||||
? data
|
||||
.where((element) => element.name!
|
||||
.toLowerCase()
|
||||
.contains(_textEditingController
|
||||
.text
|
||||
.toLowerCase()))
|
||||
.toList()
|
||||
: data;
|
||||
final entriesManga = reverse
|
||||
? entriesFilter.reversed.toList()
|
||||
: entriesFilter;
|
||||
|
||||
if (entriesFilter.isNotEmpty) {
|
||||
return displayType == DisplayType.list
|
||||
? LibraryListViewWidget(
|
||||
entriesManga: entriesManga,
|
||||
)
|
||||
: LibraryGridViewWidget(
|
||||
entriesManga: entriesManga,
|
||||
isCoverOnlyGrid:
|
||||
displayType == DisplayType.compactGrid ? false : true,
|
||||
isComfortableGrid:
|
||||
displayType == DisplayType.comfortableGrid
|
||||
? true
|
||||
: false,
|
||||
);
|
||||
if (entriesFilter.isNotEmpty) {
|
||||
return displayType == DisplayType.list
|
||||
? LibraryListViewWidget(
|
||||
entriesManga: entriesManga,
|
||||
continueReaderBtn:
|
||||
continueReaderBtn,
|
||||
downloadedChapter:
|
||||
downloadedChapter,
|
||||
language: language,
|
||||
)
|
||||
: LibraryGridViewWidget(
|
||||
entriesManga: entriesManga,
|
||||
isCoverOnlyGrid: displayType ==
|
||||
DisplayType.compactGrid
|
||||
? false
|
||||
: true,
|
||||
isComfortableGrid: displayType ==
|
||||
DisplayType.comfortableGrid
|
||||
? true
|
||||
: false,
|
||||
continueReaderBtn:
|
||||
continueReaderBtn,
|
||||
downloadedChapter:
|
||||
downloadedChapter,
|
||||
language: language,
|
||||
);
|
||||
}
|
||||
return const Center(
|
||||
child: Text("Empty Library"));
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const Center(child: Text("Empty Library"));
|
||||
},
|
||||
),
|
||||
);
|
||||
return Scaffold(
|
||||
appBar: _appBar(isNotFiltering, showNumbersOfItems, entries.length),
|
||||
body: ValueListenableBuilder<Box<ModelManga>>(
|
||||
valueListenable: ref.watch(hiveBoxMangaProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
entries =
|
||||
value.values.where((element) => element.favorite).toList();
|
||||
final data = ref
|
||||
.watch(mangaFilterResultStateProvider(mangaList: entries));
|
||||
entriesFilter = _textEditingController.text.isNotEmpty
|
||||
? data
|
||||
.where((element) => element.name!
|
||||
.toLowerCase()
|
||||
.contains(
|
||||
_textEditingController.text.toLowerCase()))
|
||||
.toList()
|
||||
: data;
|
||||
final entriesManga =
|
||||
reverse ? entriesFilter.reversed.toList() : entriesFilter;
|
||||
|
||||
if (entriesFilter.isNotEmpty) {
|
||||
return displayType == DisplayType.list
|
||||
? LibraryListViewWidget(
|
||||
entriesManga: entriesManga,
|
||||
continueReaderBtn: continueReaderBtn,
|
||||
downloadedChapter: downloadedChapter,
|
||||
language: language,
|
||||
)
|
||||
: LibraryGridViewWidget(
|
||||
entriesManga: entriesManga,
|
||||
isCoverOnlyGrid:
|
||||
displayType == DisplayType.compactGrid
|
||||
? false
|
||||
: true,
|
||||
isComfortableGrid:
|
||||
displayType == DisplayType.comfortableGrid
|
||||
? true
|
||||
: false,
|
||||
continueReaderBtn: continueReaderBtn,
|
||||
downloadedChapter: downloadedChapter,
|
||||
language: language,
|
||||
);
|
||||
}
|
||||
return const Center(child: Text("Empty Library"));
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
_showDraggableMenu() {
|
||||
late TabController tabBarController;
|
||||
tabBarController = TabController(length: 3, vsync: this);
|
||||
tabBarController.animateTo(0);
|
||||
DraggableMenu.open(
|
||||
context,
|
||||
DraggableMenu(
|
||||
barItem: Container(),
|
||||
uiType: DraggableMenuUiType.classic,
|
||||
expandable: false,
|
||||
maxHeight: mediaHeight(context, 0.4),
|
||||
fastDrag: false,
|
||||
minimizeBeforeFastDrag: false,
|
||||
uiType: DraggableMenuUiType.softModern,
|
||||
expandable: true,
|
||||
expandedHeight: mediaHeight(context, 0.8),
|
||||
maxHeight: mediaHeight(context, 0.5),
|
||||
minimizeBeforeFastDrag: true,
|
||||
child: DefaultTabController(
|
||||
length: 3,
|
||||
child: Scaffold(
|
||||
|
|
@ -220,8 +281,6 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
.notifier)
|
||||
.update();
|
||||
});
|
||||
|
||||
// _refreshData();
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
|
@ -237,7 +296,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
ref
|
||||
.read(libraryReverseListStateProvider
|
||||
.notifier)
|
||||
.setLibraryReverseList(!reverse);
|
||||
.set(!reverse);
|
||||
},
|
||||
dense: true,
|
||||
leading: Icon(reverse
|
||||
|
|
@ -253,25 +312,160 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
ref.watch(libraryDisplayTypeStateProvider);
|
||||
final displayV = ref
|
||||
.read(libraryDisplayTypeStateProvider.notifier);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
for (var i = 0;
|
||||
i < DisplayType.values.length;
|
||||
i++)
|
||||
RadioListTile<DisplayType>(
|
||||
title: Text(
|
||||
displayV.getLibraryDisplayTypeName(
|
||||
DisplayType.values[i].name)),
|
||||
value: DisplayType.values[i],
|
||||
groupValue: displayV
|
||||
.getLibraryDisplayTypeValue(display),
|
||||
selected: true,
|
||||
onChanged: (value) {
|
||||
displayV.setLibraryDisplayType(value!);
|
||||
},
|
||||
final showCategoryTabs =
|
||||
ref.watch(libraryShowCategoryTabsStateProvider);
|
||||
final continueReaderBtn = ref.watch(
|
||||
libraryShowContinueReadingButtonStateProvider);
|
||||
final showNumbersOfItems = ref
|
||||
.watch(libraryShowNumbersOfItemsStateProvider);
|
||||
final downloadedChapter = ref
|
||||
.watch(libraryDownloadedChaptersStateProvider);
|
||||
final language =
|
||||
ref.watch(libraryLanguageStateProvider);
|
||||
return SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20, top: 10),
|
||||
child: Row(
|
||||
children: const [
|
||||
Text("Display mode"),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
Column(
|
||||
children: DisplayType.values
|
||||
.map(
|
||||
(e) => RadioListTile<DisplayType>(
|
||||
title: Text(
|
||||
displayV
|
||||
.getLibraryDisplayTypeName(
|
||||
e.name),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge!
|
||||
.color,
|
||||
fontSize: 14),
|
||||
),
|
||||
value: e,
|
||||
groupValue: displayV
|
||||
.getLibraryDisplayTypeValue(
|
||||
display),
|
||||
selected: true,
|
||||
onChanged: (value) {
|
||||
displayV.setLibraryDisplayType(
|
||||
value!);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList()),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20, top: 10),
|
||||
child: Row(
|
||||
children: const [
|
||||
Text("Badges"),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 10, top: 5),
|
||||
child: Column(
|
||||
children: [
|
||||
ListTileChapterFilter(
|
||||
label: "Downloaded chapters",
|
||||
type: downloadedChapter ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryDownloadedChaptersStateProvider
|
||||
.notifier)
|
||||
.set(!downloadedChapter);
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
label: "Language",
|
||||
type: language ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryLanguageStateProvider
|
||||
.notifier)
|
||||
.set(!language);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20, top: 10),
|
||||
child: Row(
|
||||
children: const [
|
||||
Text("Tabs"),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 10, top: 5),
|
||||
child: Column(
|
||||
children: [
|
||||
ListTileChapterFilter(
|
||||
label: "Show category tabs",
|
||||
type: showCategoryTabs ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryShowCategoryTabsStateProvider
|
||||
.notifier)
|
||||
.set(!showCategoryTabs);
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
label: "Show numbers of items",
|
||||
type: showNumbersOfItems ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryShowNumbersOfItemsStateProvider
|
||||
.notifier)
|
||||
.set(!showNumbersOfItems);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 20, top: 10),
|
||||
child: Row(
|
||||
children: const [
|
||||
Text("Others"),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 10, top: 5),
|
||||
child: Column(
|
||||
children: [
|
||||
ListTileChapterFilter(
|
||||
label:
|
||||
"Show continue reading button",
|
||||
type: continueReaderBtn ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
libraryShowContinueReadingButtonStateProvider
|
||||
.notifier)
|
||||
.set(!continueReaderBtn);
|
||||
}),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
]),
|
||||
|
|
@ -280,4 +474,87 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
),
|
||||
))));
|
||||
}
|
||||
|
||||
AppBar _appBar(
|
||||
bool isNotFiltering, bool showNumbersOfItems, int numberOfItems) {
|
||||
return AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
title: isSearch
|
||||
? null
|
||||
: Row(
|
||||
children: [
|
||||
Text(
|
||||
'Library',
|
||||
style: TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
if (showNumbersOfItems)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 3),
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Theme.of(context).focusColor,
|
||||
radius: 10,
|
||||
child: Text(
|
||||
numberOfItems.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
Theme.of(context).textTheme.bodySmall!.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
isSearch
|
||||
? SeachFormTextField(
|
||||
onChanged: (value) {
|
||||
setState(() {});
|
||||
},
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isSearch = false;
|
||||
});
|
||||
_textEditingController.clear();
|
||||
},
|
||||
controller: _textEditingController,
|
||||
onSuffixPressed: () {
|
||||
_textEditingController.clear();
|
||||
setState(() {});
|
||||
},
|
||||
)
|
||||
: IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isSearch = true;
|
||||
});
|
||||
_textEditingController.clear();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.search,
|
||||
)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
_showDraggableMenu();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.filter_list_sharp,
|
||||
color: isNotFiltering ? null : Colors.yellow,
|
||||
)),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Open random entry")),
|
||||
];
|
||||
},
|
||||
onSelected: (value) {}),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class LibraryReverseListState extends _$LibraryReverseListState {
|
|||
.get('libraryReverseList', defaultValue: false)!;
|
||||
}
|
||||
|
||||
void setLibraryReverseList(bool value) {
|
||||
void set(bool value) {
|
||||
state = value;
|
||||
ref.watch(hiveBoxSettingsProvider).put('libraryReverseList', value);
|
||||
}
|
||||
|
|
@ -430,3 +430,82 @@ class MangaFilterResultState extends _$MangaFilterResultState {
|
|||
bookmarkedFilterType == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
|
||||
@override
|
||||
bool build() {
|
||||
return ref
|
||||
.watch(hiveBoxSettingsProvider)
|
||||
.get('libraryShowCategoryTabs', defaultValue: false)!;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
state = value;
|
||||
ref.watch(hiveBoxSettingsProvider).put('libraryShowCategoryTabs', value);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
|
||||
@override
|
||||
bool build() {
|
||||
return ref
|
||||
.watch(hiveBoxSettingsProvider)
|
||||
.get('libraryDownloadedChapters', defaultValue: false)!;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
state = value;
|
||||
ref.watch(hiveBoxSettingsProvider).put('libraryDownloadedChapters', value);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class LibraryLanguageState extends _$LibraryLanguageState {
|
||||
@override
|
||||
bool build() {
|
||||
return ref
|
||||
.watch(hiveBoxSettingsProvider)
|
||||
.get('libraryLanguage', defaultValue: false)!;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
state = value;
|
||||
ref.watch(hiveBoxSettingsProvider).put('libraryLanguage', value);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
|
||||
@override
|
||||
bool build() {
|
||||
return ref
|
||||
.watch(hiveBoxSettingsProvider)
|
||||
.get('libraryShowNumbersOfItems', defaultValue: false)!;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
state = value;
|
||||
ref.watch(hiveBoxSettingsProvider).put('libraryShowNumbersOfItems', value);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class LibraryShowContinueReadingButtonState
|
||||
extends _$LibraryShowContinueReadingButtonState {
|
||||
@override
|
||||
bool build() {
|
||||
return ref
|
||||
.watch(hiveBoxSettingsProvider)
|
||||
.get('libraryShowContinueReadingButton', defaultValue: false)!;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
state = value;
|
||||
ref
|
||||
.watch(hiveBoxSettingsProvider)
|
||||
.put('libraryShowContinueReadingButton', value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'library_state_provider.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$libraryReverseListStateHash() =>
|
||||
r'9a9b8cc5bacc6e84a89847cc4e0ea6793c6b851e';
|
||||
r'5d9037f95ffe332019dd1d3d08b0db06d798738c';
|
||||
|
||||
/// See also [LibraryReverseListState].
|
||||
@ProviderFor(LibraryReverseListState)
|
||||
|
|
@ -24,7 +24,7 @@ final libraryReverseListStateProvider =
|
|||
|
||||
typedef _$LibraryReverseListState = AutoDisposeNotifier<bool>;
|
||||
String _$libraryDisplayTypeStateHash() =>
|
||||
r'2743481e54668fe95294194b62014f9713de2cb8';
|
||||
r'746bd6dac3600802c3ab5751b3c1def881274b3a';
|
||||
|
||||
/// See also [LibraryDisplayTypeState].
|
||||
@ProviderFor(LibraryDisplayTypeState)
|
||||
|
|
@ -41,7 +41,7 @@ final libraryDisplayTypeStateProvider =
|
|||
|
||||
typedef _$LibraryDisplayTypeState = AutoDisposeNotifier<String>;
|
||||
String _$mangaFilterDownloadedStateHash() =>
|
||||
r'12b1cb7b473e6556ea9c1a2f9c7bf44017076ff4';
|
||||
r'18ed17c06f41084cbb92b0b3300025f4e65aa413';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -161,7 +161,7 @@ class MangaFilterDownloadedStateProvider
|
|||
}
|
||||
|
||||
String _$mangaFilterUnreadStateHash() =>
|
||||
r'4b9172bbb95ebca0759946328b1fbdacf07392b1';
|
||||
r'5eed6ec9f46f1562d48eb89a078f666ed5b466d8';
|
||||
|
||||
abstract class _$MangaFilterUnreadState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
|
|
@ -260,7 +260,7 @@ class MangaFilterUnreadStateProvider
|
|||
}
|
||||
|
||||
String _$mangaFilterStartedStateHash() =>
|
||||
r'9b3c27078f42f624e3f3fdd255573a3279a4efed';
|
||||
r'cf5440f02e8454d75de4f311f945b33f73668ea2';
|
||||
|
||||
abstract class _$MangaFilterStartedState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
|
|
@ -359,7 +359,7 @@ class MangaFilterStartedStateProvider
|
|||
}
|
||||
|
||||
String _$mangaFilterBookmarkedStateHash() =>
|
||||
r'88b9ef0b5a65735525a0141c6e7397d9aa7e27ff';
|
||||
r'cdeeb68e7428e4856db3551443c70e28c3c7f95d';
|
||||
|
||||
abstract class _$MangaFilterBookmarkedState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
|
|
@ -458,7 +458,7 @@ class MangaFilterBookmarkedStateProvider
|
|||
}
|
||||
|
||||
String _$mangaFilterResultStateHash() =>
|
||||
r'5ec8cf6917ccc72d5eef7f2e7b308725563e4831';
|
||||
r'fb5c27326f49a7e361ac19b97b511f1d8ab50920';
|
||||
|
||||
abstract class _$MangaFilterResultState
|
||||
extends BuildlessAutoDisposeNotifier<List<ModelManga>> {
|
||||
|
|
@ -555,4 +555,91 @@ class MangaFilterResultStateProvider extends AutoDisposeNotifierProviderImpl<
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$libraryShowCategoryTabsStateHash() =>
|
||||
r'0ee90372d42a11638479aadcf8ea5e688bb48369';
|
||||
|
||||
/// See also [LibraryShowCategoryTabsState].
|
||||
@ProviderFor(LibraryShowCategoryTabsState)
|
||||
final libraryShowCategoryTabsStateProvider =
|
||||
AutoDisposeNotifierProvider<LibraryShowCategoryTabsState, bool>.internal(
|
||||
LibraryShowCategoryTabsState.new,
|
||||
name: r'libraryShowCategoryTabsStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryShowCategoryTabsStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$LibraryShowCategoryTabsState = AutoDisposeNotifier<bool>;
|
||||
String _$libraryDownloadedChaptersStateHash() =>
|
||||
r'bdbb37edcd547e8f34df39d9221bb85051f765ae';
|
||||
|
||||
/// See also [LibraryDownloadedChaptersState].
|
||||
@ProviderFor(LibraryDownloadedChaptersState)
|
||||
final libraryDownloadedChaptersStateProvider =
|
||||
AutoDisposeNotifierProvider<LibraryDownloadedChaptersState, bool>.internal(
|
||||
LibraryDownloadedChaptersState.new,
|
||||
name: r'libraryDownloadedChaptersStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryDownloadedChaptersStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$LibraryDownloadedChaptersState = AutoDisposeNotifier<bool>;
|
||||
String _$libraryLanguageStateHash() =>
|
||||
r'b454724faeda5de41a67952cf9a80366fb72be9c';
|
||||
|
||||
/// See also [LibraryLanguageState].
|
||||
@ProviderFor(LibraryLanguageState)
|
||||
final libraryLanguageStateProvider =
|
||||
AutoDisposeNotifierProvider<LibraryLanguageState, bool>.internal(
|
||||
LibraryLanguageState.new,
|
||||
name: r'libraryLanguageStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryLanguageStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$LibraryLanguageState = AutoDisposeNotifier<bool>;
|
||||
String _$libraryShowNumbersOfItemsStateHash() =>
|
||||
r'f6eeb5df01cee601f05e442229830f64891a5fe9';
|
||||
|
||||
/// See also [LibraryShowNumbersOfItemsState].
|
||||
@ProviderFor(LibraryShowNumbersOfItemsState)
|
||||
final libraryShowNumbersOfItemsStateProvider =
|
||||
AutoDisposeNotifierProvider<LibraryShowNumbersOfItemsState, bool>.internal(
|
||||
LibraryShowNumbersOfItemsState.new,
|
||||
name: r'libraryShowNumbersOfItemsStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryShowNumbersOfItemsStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$LibraryShowNumbersOfItemsState = AutoDisposeNotifier<bool>;
|
||||
String _$libraryShowContinueReadingButtonStateHash() =>
|
||||
r'4d5553dc605e87714b3c23f54c52c1911910a8aa';
|
||||
|
||||
/// See also [LibraryShowContinueReadingButtonState].
|
||||
@ProviderFor(LibraryShowContinueReadingButtonState)
|
||||
final libraryShowContinueReadingButtonStateProvider =
|
||||
AutoDisposeNotifierProvider<LibraryShowContinueReadingButtonState,
|
||||
bool>.internal(
|
||||
LibraryShowContinueReadingButtonState.new,
|
||||
name: r'libraryShowContinueReadingButtonStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryShowContinueReadingButtonStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$LibraryShowContinueReadingButtonState = AutoDisposeNotifier<bool>;
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/manga_reader.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/utils/colors.dart';
|
||||
import 'package:mangayomi/views/manga/download/download_model.dart';
|
||||
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.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';
|
||||
|
|
@ -11,11 +17,17 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
final bool isCoverOnlyGrid;
|
||||
final bool isComfortableGrid;
|
||||
final List<ModelManga> entriesManga;
|
||||
final bool language;
|
||||
final bool downloadedChapter;
|
||||
final bool continueReaderBtn;
|
||||
const LibraryGridViewWidget(
|
||||
{super.key,
|
||||
required this.entriesManga,
|
||||
required this.isCoverOnlyGrid,
|
||||
this.isComfortableGrid = false});
|
||||
this.isComfortableGrid = false,
|
||||
required this.language,
|
||||
required this.downloadedChapter,
|
||||
required this.continueReaderBtn});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -51,20 +63,177 @@ class LibraryGridViewWidget extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(3),
|
||||
color: generalColor(context),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(1),
|
||||
child: Text(
|
||||
entriesManga[index].chapters!.length.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
if (downloadedChapter)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 5),
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
List nbrDown = [];
|
||||
for (var i = 0;
|
||||
i <
|
||||
entriesManga[index]
|
||||
.chapters!
|
||||
.length;
|
||||
i++) {
|
||||
final entries = ref
|
||||
.watch(
|
||||
hiveBoxMangaDownloadsProvider)
|
||||
.values
|
||||
.where((element) =>
|
||||
element
|
||||
.modelManga
|
||||
.chapters![element.index]
|
||||
.name ==
|
||||
entriesManga[index]
|
||||
.chapters![i]
|
||||
.name)
|
||||
.toList();
|
||||
if (entries.isNotEmpty &&
|
||||
entries.first.isDownload) {
|
||||
nbrDown.add(entries.first);
|
||||
}
|
||||
}
|
||||
if (nbrDown.isNotEmpty) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
const BorderRadius.only(
|
||||
topLeft: Radius.circular(3),
|
||||
bottomLeft:
|
||||
Radius.circular(3)),
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 3, right: 3),
|
||||
child: Text(
|
||||
nbrDown.length.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 3),
|
||||
child: Text(
|
||||
entriesManga[index]
|
||||
.chapters!
|
||||
.length
|
||||
.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
))
|
||||
)),
|
||||
if (language)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(3),
|
||||
bottomLeft: Radius.circular(3)),
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 3, right: 3),
|
||||
child: Text(
|
||||
entriesManga[index].lang!.toUpperCase(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
if (!isComfortableGrid)
|
||||
if (!isCoverOnlyGrid)
|
||||
BottomTextWidget(text: entriesManga[index].name!)
|
||||
BottomTextWidget(text: entriesManga[index].name!),
|
||||
if (continueReaderBtn)
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(9),
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
return ValueListenableBuilder<Box>(
|
||||
valueListenable: ref
|
||||
.watch(hiveBoxMangaInfoProvider)
|
||||
.listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.get(
|
||||
"${entriesManga[index].lang}-${entriesManga[index].source}/${entriesManga[index].name}-chapter_index",
|
||||
defaultValue: '');
|
||||
final incognitoMode =
|
||||
ref.watch(incognitoModeStateProvider);
|
||||
|
||||
if (entries.isNotEmpty && !incognitoMode) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
pushMangaReaderView(
|
||||
context: context,
|
||||
modelManga: entriesManga[index],
|
||||
index: int.parse(entries.toString()));
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: generalColor(context)
|
||||
.withOpacity(0.7),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(7),
|
||||
child: Icon(
|
||||
Icons.play_arrow,
|
||||
size: 19,
|
||||
color: Colors.white,
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
pushMangaReaderView(
|
||||
context: context,
|
||||
modelManga: entriesManga[index],
|
||||
index: entriesManga[index]
|
||||
.chapters!
|
||||
.length -
|
||||
1);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: generalColor(context)
|
||||
.withOpacity(0.7),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(7),
|
||||
child: Icon(
|
||||
Icons.play_arrow,
|
||||
size: 19,
|
||||
color: Colors.white,
|
||||
)),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
)))
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,27 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/manga_reader.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/utils/colors.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
||||
import 'package:mangayomi/views/widgets/listview_widget.dart';
|
||||
|
||||
class LibraryListViewWidget extends StatelessWidget {
|
||||
final List<ModelManga> entriesManga;
|
||||
const LibraryListViewWidget({super.key, required this.entriesManga});
|
||||
final bool language;
|
||||
final bool downloadedChapter;
|
||||
final bool continueReaderBtn;
|
||||
const LibraryListViewWidget(
|
||||
{super.key,
|
||||
required this.entriesManga,
|
||||
required this.language,
|
||||
required this.downloadedChapter,
|
||||
required this.continueReaderBtn});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -27,25 +40,27 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(5),
|
||||
bottomLeft: Radius.circular(5)),
|
||||
child: cachedNetworkImage(
|
||||
imageUrl: entriesManga[index].imageUrl!,
|
||||
width: 40,
|
||||
height: 40,
|
||||
fit: BoxFit.cover),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: SizedBox(
|
||||
width: mediaWidth(context, 0.7),
|
||||
child: Text(entriesManga[index].name!)),
|
||||
),
|
||||
],
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(5),
|
||||
bottomLeft: Radius.circular(5)),
|
||||
child: cachedNetworkImage(
|
||||
imageUrl: entriesManga[index].imageUrl!,
|
||||
width: 40,
|
||||
height: 40,
|
||||
fit: BoxFit.cover),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Text(entriesManga[index].name!),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
|
|
@ -53,15 +68,162 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
color: generalColor(context)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(1),
|
||||
child: Text(
|
||||
entriesManga[index].chapters!.length.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
child: SizedBox(
|
||||
height: 22,
|
||||
child: Row(
|
||||
children: [
|
||||
if (downloadedChapter)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 5),
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
List nbrDown = [];
|
||||
for (var i = 0;
|
||||
i <
|
||||
entriesManga[index]
|
||||
.chapters!
|
||||
.length;
|
||||
i++) {
|
||||
final entries = ref
|
||||
.watch(hiveBoxMangaDownloadsProvider)
|
||||
.values
|
||||
.where((element) =>
|
||||
element
|
||||
.modelManga
|
||||
.chapters![element.index]
|
||||
.name ==
|
||||
entriesManga[index]
|
||||
.chapters![i]
|
||||
.name)
|
||||
.toList();
|
||||
if (entries.isNotEmpty &&
|
||||
entries.first.isDownload) {
|
||||
nbrDown.add(entries.first);
|
||||
}
|
||||
}
|
||||
if (nbrDown.isNotEmpty) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(3),
|
||||
bottomLeft: Radius.circular(3)),
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 3, right: 3),
|
||||
child: Text(
|
||||
nbrDown.length.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 3),
|
||||
child: Text(
|
||||
entriesManga[index].chapters!.length.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
if (language)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topRight: Radius.circular(3),
|
||||
bottomRight: Radius.circular(3)),
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 3, right: 3),
|
||||
child: Text(
|
||||
entriesManga[index].lang!.toUpperCase(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
if (continueReaderBtn)
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
return ValueListenableBuilder<Box>(
|
||||
valueListenable: ref
|
||||
.watch(hiveBoxMangaInfoProvider)
|
||||
.listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.get(
|
||||
"${entriesManga[index].lang}-${entriesManga[index].source}/${entriesManga[index].name}-chapter_index",
|
||||
defaultValue: '');
|
||||
final incognitoMode =
|
||||
ref.watch(incognitoModeStateProvider);
|
||||
|
||||
if (entries.isNotEmpty && !incognitoMode) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
pushMangaReaderView(
|
||||
context: context,
|
||||
modelManga: entriesManga[index],
|
||||
index: int.parse(entries.toString()));
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: generalColor(context)
|
||||
.withOpacity(0.7),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(7),
|
||||
child: Icon(
|
||||
Icons.play_arrow,
|
||||
size: 19,
|
||||
color: Colors.white,
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
pushMangaReaderView(
|
||||
context: context,
|
||||
modelManga: entriesManga[index],
|
||||
index: entriesManga[index]
|
||||
.chapters!
|
||||
.length -
|
||||
1);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: generalColor(context)
|
||||
.withOpacity(0.7),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(7),
|
||||
child: Icon(
|
||||
Icons.play_arrow,
|
||||
size: 19,
|
||||
color: Colors.white,
|
||||
)),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/categories.dart';
|
||||
import 'package:mangayomi/models/manga_reader.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
|
|
@ -9,6 +11,7 @@ import 'package:mangayomi/utils/colors.dart';
|
|||
import 'package:mangayomi/utils/media_query.dart';
|
||||
import 'package:mangayomi/views/manga/detail/manga_detail_view.dart';
|
||||
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
||||
import 'package:mangayomi/views/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
||||
|
||||
class MangaDetailsView extends ConsumerStatefulWidget {
|
||||
|
|
@ -242,7 +245,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
dateAdded: widget.modelManga.dateAdded,
|
||||
lastUpdate: widget.modelManga.lastUpdate,
|
||||
chapters: widget.modelManga.chapters,
|
||||
category: widget.modelManga.category,
|
||||
categories: [],
|
||||
lastRead: widget.modelManga.lastRead);
|
||||
manga.put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
|
|
@ -275,26 +278,35 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
Theme.of(context).scaffoldBackgroundColor,
|
||||
elevation: 0),
|
||||
onPressed: () {
|
||||
_setFavorite(true);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga.imageUrl,
|
||||
name: widget.modelManga.name,
|
||||
genre: widget.modelManga.genre,
|
||||
author: widget.modelManga.author,
|
||||
status: widget.modelManga.status,
|
||||
description: widget.modelManga.description,
|
||||
favorite: true,
|
||||
link: widget.modelManga.link,
|
||||
source: widget.modelManga.source,
|
||||
lang: widget.modelManga.lang,
|
||||
dateAdded: DateTime.now().microsecondsSinceEpoch,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: widget.modelManga.chapters,
|
||||
category: null,
|
||||
lastRead: '');
|
||||
manga.put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
model);
|
||||
final checkCategoryList = ref
|
||||
.watch(hiveBoxCategoriesProvider)
|
||||
.values
|
||||
.toList()
|
||||
.isNotEmpty;
|
||||
if (checkCategoryList) {
|
||||
_openCategory(manga);
|
||||
} else {
|
||||
_setFavorite(true);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga.imageUrl,
|
||||
name: widget.modelManga.name,
|
||||
genre: widget.modelManga.genre,
|
||||
author: widget.modelManga.author,
|
||||
status: widget.modelManga.status,
|
||||
description: widget.modelManga.description,
|
||||
favorite: true,
|
||||
link: widget.modelManga.link,
|
||||
source: widget.modelManga.source,
|
||||
lang: widget.modelManga.lang,
|
||||
dateAdded: DateTime.now().microsecondsSinceEpoch,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: widget.modelManga.chapters,
|
||||
categories: [],
|
||||
lastRead: '');
|
||||
manga.put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
model);
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
|
|
@ -324,26 +336,35 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
elevation: 0),
|
||||
onPressed: () {
|
||||
_setFavorite(true);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga.imageUrl,
|
||||
name: widget.modelManga.name,
|
||||
genre: widget.modelManga.genre,
|
||||
author: widget.modelManga.author,
|
||||
status: widget.modelManga.status,
|
||||
description: widget.modelManga.description,
|
||||
favorite: true,
|
||||
link: widget.modelManga.link,
|
||||
source: widget.modelManga.source,
|
||||
lang: widget.modelManga.lang,
|
||||
dateAdded: DateTime.now().microsecondsSinceEpoch,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: widget.modelManga.chapters,
|
||||
category: null,
|
||||
lastRead: '');
|
||||
manga.put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
model);
|
||||
final checkCategoryList = ref
|
||||
.watch(hiveBoxCategoriesProvider)
|
||||
.values
|
||||
.toList()
|
||||
.isNotEmpty;
|
||||
if (checkCategoryList) {
|
||||
_openCategory(manga);
|
||||
} else {
|
||||
_setFavorite(true);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga.imageUrl,
|
||||
name: widget.modelManga.name,
|
||||
genre: widget.modelManga.genre,
|
||||
author: widget.modelManga.author,
|
||||
status: widget.modelManga.status,
|
||||
description: widget.modelManga.description,
|
||||
favorite: true,
|
||||
link: widget.modelManga.link,
|
||||
source: widget.modelManga.source,
|
||||
lang: widget.modelManga.lang,
|
||||
dateAdded: DateTime.now().microsecondsSinceEpoch,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: widget.modelManga.chapters,
|
||||
categories: [],
|
||||
lastRead: '');
|
||||
manga.put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
model);
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
|
|
@ -374,4 +395,105 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
_openCategory(Box<ModelManga> manga) {
|
||||
List<int> categoryIds = [];
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"Set categories",
|
||||
),
|
||||
content: SizedBox(
|
||||
width: mediaWidth(context, 0.8),
|
||||
child: ValueListenableBuilder<Box<CategoriesModel>>(
|
||||
valueListenable:
|
||||
ref.watch(hiveBoxCategoriesProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values.toList();
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: entries.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTileChapterFilter(
|
||||
label: entries[index].name,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (categoryIds.contains(entries[index].id)) {
|
||||
categoryIds.remove(entries[index].id);
|
||||
} else {
|
||||
categoryIds.add(entries[index].id);
|
||||
}
|
||||
});
|
||||
},
|
||||
type: categoryIds.contains(entries[index].id)
|
||||
? 1
|
||||
: 0,
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories");
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text("Edit")),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text("Cancel")),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_setFavorite(true);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga.imageUrl,
|
||||
name: widget.modelManga.name,
|
||||
genre: widget.modelManga.genre,
|
||||
author: widget.modelManga.author,
|
||||
status: widget.modelManga.status,
|
||||
description: widget.modelManga.description,
|
||||
favorite: true,
|
||||
link: widget.modelManga.link,
|
||||
source: widget.modelManga.source,
|
||||
lang: widget.modelManga.lang,
|
||||
dateAdded:
|
||||
DateTime.now().microsecondsSinceEpoch,
|
||||
lastUpdate:
|
||||
DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: widget.modelManga.chapters,
|
||||
categories: categoryIds,
|
||||
lastRead: '');
|
||||
manga.put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
model);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text(
|
||||
"OK",
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
|
|||
dateAdded: widget.modelManga.dateAdded,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: chapters,
|
||||
category: widget.modelManga.category,
|
||||
categories: widget.modelManga.categories,
|
||||
lastRead: widget.modelManga.lastRead);
|
||||
ref.watch(hiveBoxMangaProvider).put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
|
|
|
|||
|
|
@ -502,7 +502,7 @@ ModelManga modelMangaWithNewChapValue(
|
|||
dateAdded: modelManga.dateAdded,
|
||||
lastUpdate: modelManga.lastUpdate,
|
||||
chapters: chapters,
|
||||
category: modelManga.category,
|
||||
categories: modelManga.categories,
|
||||
lastRead: modelManga.lastRead);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ final isExtendedStateProvider =
|
|||
);
|
||||
|
||||
typedef _$IsExtendedState = AutoDisposeNotifier<bool>;
|
||||
String _$reverseMangaStateHash() => r'ba21cdabf4a5e60e9c31b09a93080ccae84e3bd4';
|
||||
String _$reverseMangaStateHash() => r'27a74f99810dac3d27d428a107a397e03eb2835d';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -190,7 +190,7 @@ class ReverseMangaStateProvider
|
|||
}
|
||||
|
||||
String _$chapterFilterDownloadedStateHash() =>
|
||||
r'46dca943e064d5f70968c711812091783e0a4039';
|
||||
r'ea2313a3f81e408cdea77e98d82510e824ddd6a4';
|
||||
|
||||
abstract class _$ChapterFilterDownloadedState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
|
|
@ -290,7 +290,7 @@ class ChapterFilterDownloadedStateProvider
|
|||
}
|
||||
|
||||
String _$chapterFilterUnreadStateHash() =>
|
||||
r'48076800725c22f04493653deec4e946cb71d195';
|
||||
r'54a6bd0ace5db2262298ec51a7a99149aeaff047';
|
||||
|
||||
abstract class _$ChapterFilterUnreadState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
|
|
@ -389,7 +389,7 @@ class ChapterFilterUnreadStateProvider
|
|||
}
|
||||
|
||||
String _$chapterFilterBookmarkedStateHash() =>
|
||||
r'4772ce2506d0c939b549c8661cd3b62cae853e20';
|
||||
r'316ae7f6d11556927aa160ab950585e3e74fc8e1';
|
||||
|
||||
abstract class _$ChapterFilterBookmarkedState
|
||||
extends BuildlessAutoDisposeNotifier<int> {
|
||||
|
|
@ -489,7 +489,7 @@ class ChapterFilterBookmarkedStateProvider
|
|||
}
|
||||
|
||||
String _$chapterFilterResultStateHash() =>
|
||||
r'85ab18048c228f674211c8254d7efedb92152b8f';
|
||||
r'a0c0bccb457db8ccfba52e2b7e36a1f6e2b6afe3';
|
||||
|
||||
abstract class _$ChapterFilterResultState
|
||||
extends BuildlessAutoDisposeNotifier<ModelManga> {
|
||||
|
|
@ -588,7 +588,7 @@ class ChapterFilterResultStateProvider extends AutoDisposeNotifierProviderImpl<
|
|||
}
|
||||
|
||||
String _$chapterSetIsBookmarkStateHash() =>
|
||||
r'a53f9acaea333287e229c391ba01c9da22a59b0f';
|
||||
r'1be8afbfd3ebd0a519922f315d204d60409bed57';
|
||||
|
||||
abstract class _$ChapterSetIsBookmarkState
|
||||
extends BuildlessAutoDisposeNotifier<dynamic> {
|
||||
|
|
@ -687,7 +687,7 @@ class ChapterSetIsBookmarkStateProvider extends AutoDisposeNotifierProviderImpl<
|
|||
}
|
||||
|
||||
String _$chapterSetIsReadStateHash() =>
|
||||
r'9435f9d17d5d1fdcfab0279e93d964bd2e4d1fbb';
|
||||
r'fafd4503e4e65d48f157893de2b3a2234f4b20c7';
|
||||
|
||||
abstract class _$ChapterSetIsReadState
|
||||
extends BuildlessAutoDisposeNotifier<dynamic> {
|
||||
|
|
@ -786,7 +786,7 @@ class ChapterSetIsReadStateProvider
|
|||
}
|
||||
|
||||
String _$chapterSetDownloadStateHash() =>
|
||||
r'9c27161d2eedd2e8d55281d9f5640e4459926d6f';
|
||||
r'299986f635cf64cf09aafbd7da373fa3e93ac8fc';
|
||||
|
||||
abstract class _$ChapterSetDownloadState
|
||||
extends BuildlessAutoDisposeNotifier<dynamic> {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'download_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$downloadChapterHash() => r'39625ed8cba923709fe7c76788e334bec1d8bcc3';
|
||||
String _$downloadChapterHash() => r'982e5db78e716894f63b97598709e29098c3eb8f';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class ReaderController extends _$ReaderController {
|
|||
dateAdded: getModelManga().dateAdded,
|
||||
lastUpdate: getModelManga().lastUpdate,
|
||||
chapters: chap,
|
||||
category: getModelManga().category,
|
||||
categories: getModelManga().categories,
|
||||
lastRead: getModelManga().lastRead);
|
||||
ref
|
||||
.watch(hiveBoxMangaProvider)
|
||||
|
|
@ -177,7 +177,7 @@ class ReaderController extends _$ReaderController {
|
|||
dateAdded: getModelManga().dateAdded,
|
||||
lastUpdate: getModelManga().lastUpdate,
|
||||
chapters: chap,
|
||||
category: getModelManga().category,
|
||||
categories: getModelManga().categories,
|
||||
lastRead: getModelManga().lastRead);
|
||||
ref
|
||||
.watch(hiveBoxMangaProvider)
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class ReaderModeAdapter extends TypeAdapter<ReaderMode> {
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$currentIndexHash() => r'287404f12bc984052a83e97beb3ff335e820e8de';
|
||||
String _$currentIndexHash() => r'b25073058aa2f1a392a4591d8812a61e752061ef';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -182,7 +182,7 @@ class CurrentIndexProvider
|
|||
}
|
||||
}
|
||||
|
||||
String _$readerControllerHash() => r'56c832982f94aab78b30439b025177b7f3851cec';
|
||||
String _$readerControllerHash() => r'a389f9b08001c6863a651f6c2ed3d1b18588d5b0';
|
||||
|
||||
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
|
||||
late final MangaReaderModel mangaReaderModel;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class MoreScreen extends StatelessWidget {
|
|||
onTap: () {
|
||||
context.push('/categories');
|
||||
},
|
||||
icon: Icons.label_rounded,
|
||||
icon: Icons.label_outline_rounded,
|
||||
title: 'Categories',
|
||||
),
|
||||
const Divider(),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'blend_level_state_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$blendLevelStateHash() => r'20a7e4e5cb5ff9d60bcf60c2c7e9b36584c3acb0';
|
||||
String _$blendLevelStateHash() => r'b1a14a5ff8ddf89164aec31c92c24ec9585ce0f5';
|
||||
|
||||
/// See also [BlendLevelState].
|
||||
@ProviderFor(BlendLevelState)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'flex_scheme_color_state_provider.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$flexSchemeColorStateHash() =>
|
||||
r'825680702e419e5eb921e251312ffd4ba3303a2c';
|
||||
r'84c6afce63762e5704c548caf9059f922a9936b8';
|
||||
|
||||
/// See also [FlexSchemeColorState].
|
||||
@ProviderFor(FlexSchemeColorState)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'theme_mode_state_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$themeModeStateHash() => r'ae86c33659103122399492e5409a0e947b0c6292';
|
||||
String _$themeModeStateHash() => r'ffb06bbf255e51a6f14424280f7874b1a11062ec';
|
||||
|
||||
/// See also [ThemeModeState].
|
||||
@ProviderFor(ThemeModeState)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/categories.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/views/more/settings/categoties/widgets/custom_textfield.dart';
|
||||
import 'package:random_string/random_string.dart';
|
||||
|
||||
class CategoriesScreen extends ConsumerStatefulWidget {
|
||||
const CategoriesScreen({super.key});
|
||||
|
|
@ -12,6 +14,7 @@ class CategoriesScreen extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
||||
List<CategoriesModel> entries = [];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
|
@ -21,10 +24,122 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
|||
body: ValueListenableBuilder<Box<CategoriesModel>>(
|
||||
valueListenable: ref.watch(hiveBoxCategoriesProvider).listenable(),
|
||||
builder: (context, value, child) {
|
||||
final entries = value.values.toList();
|
||||
entries = value.values.toList();
|
||||
if (entries.isNotEmpty) {
|
||||
return ListView.builder(
|
||||
itemBuilder: (context, index) {},
|
||||
itemCount: entries.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Card(
|
||||
child: Column(
|
||||
children: [
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(0),
|
||||
bottomRight: Radius.circular(0),
|
||||
topRight: Radius.circular(10),
|
||||
topLeft: Radius.circular(10)))),
|
||||
onPressed: () {
|
||||
_renameCategory(entries[index]);
|
||||
},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
const Icon(Icons.label_outline_rounded),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(child: Text(entries[index].name))
|
||||
],
|
||||
)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: const [
|
||||
SizedBox(width: 10),
|
||||
Icon(Icons.arrow_drop_up_outlined),
|
||||
SizedBox(width: 10),
|
||||
Icon(Icons.arrow_drop_down_outlined)
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
_renameCategory(entries[index]);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.mode_edit_outline_outlined)),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"Delete category",
|
||||
),
|
||||
content: Text(
|
||||
"Do you wish to delete the category"
|
||||
' "${entries[index].name}"?'),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context);
|
||||
},
|
||||
child: const Text(
|
||||
"Cancel")),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.watch(
|
||||
hiveBoxCategoriesProvider)
|
||||
.delete(entries[
|
||||
index]
|
||||
.id
|
||||
.toString());
|
||||
Navigator.pop(
|
||||
context);
|
||||
},
|
||||
child: const Text(
|
||||
"OK",
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.delete_outlined))
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return const Center(
|
||||
|
|
@ -40,41 +155,28 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
|||
}),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
bool isExist = false;
|
||||
final controller = TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
final controller = TextEditingController();
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"Add category",
|
||||
),
|
||||
content: TextFormField(
|
||||
autofocus: true,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.text,
|
||||
onChanged: (s) {
|
||||
setState(() {});
|
||||
},
|
||||
onFieldSubmitted: (s) {
|
||||
setState(() {});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
labelText: "Name",
|
||||
filled: true,
|
||||
fillColor: Colors.transparent,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).primaryColor)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).primaryColor)),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).primaryColor))),
|
||||
),
|
||||
content: CustomTextFormField(
|
||||
controller: controller,
|
||||
entries: entries,
|
||||
context: context,
|
||||
exist: (value) {
|
||||
setState(() {
|
||||
isExist = value;
|
||||
});
|
||||
},
|
||||
isExist: isExist,
|
||||
val: (val) {}),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
|
|
@ -88,19 +190,29 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
|||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: controller.text.isEmpty
|
||||
onPressed: controller.text.isEmpty || isExist
|
||||
? null
|
||||
: () {
|
||||
String randomId = randomNumeric(10);
|
||||
ref
|
||||
.watch(hiveBoxCategoriesProvider)
|
||||
.put(
|
||||
randomId,
|
||||
CategoriesModel(
|
||||
id: int.parse(randomId),
|
||||
name: controller.text,
|
||||
));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(
|
||||
"Add",
|
||||
style: TextStyle(
|
||||
color: controller.text.isEmpty
|
||||
? Theme.of(context)
|
||||
.primaryColor
|
||||
.withOpacity(0.2)
|
||||
: null),
|
||||
color:
|
||||
controller.text.isEmpty || isExist
|
||||
? Theme.of(context)
|
||||
.primaryColor
|
||||
.withOpacity(0.2)
|
||||
: null),
|
||||
)),
|
||||
],
|
||||
)
|
||||
|
|
@ -121,4 +233,78 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
|
|||
)),
|
||||
);
|
||||
}
|
||||
|
||||
_renameCategory(CategoriesModel category) {
|
||||
bool isExist = false;
|
||||
final controller = TextEditingController(text: category.name);
|
||||
bool isSameName = controller.text == category.name;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"Rename category",
|
||||
),
|
||||
content: CustomTextFormField(
|
||||
controller: controller,
|
||||
entries: entries,
|
||||
context: context,
|
||||
exist: (value) {
|
||||
setState(() {
|
||||
isExist = value;
|
||||
});
|
||||
},
|
||||
isExist: isExist,
|
||||
name: category.name,
|
||||
val: (val) {
|
||||
setState(() {
|
||||
isSameName = controller.text == category.name;
|
||||
});
|
||||
}),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text("Cancel")),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed:
|
||||
controller.text.isEmpty || isExist || isSameName
|
||||
? null
|
||||
: () {
|
||||
ref.watch(hiveBoxCategoriesProvider).put(
|
||||
category.id.toString(),
|
||||
CategoriesModel(
|
||||
id: category.id,
|
||||
name: controller.text,
|
||||
));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(
|
||||
"OK",
|
||||
style: TextStyle(
|
||||
color: controller.text.isEmpty ||
|
||||
isExist ||
|
||||
isSameName
|
||||
? Theme.of(context)
|
||||
.primaryColor
|
||||
.withOpacity(0.2)
|
||||
: null),
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:mangayomi/models/categories.dart';
|
||||
|
||||
class CustomTextFormField extends StatelessWidget {
|
||||
final TextEditingController controller;
|
||||
final List<CategoriesModel> entries;
|
||||
final BuildContext context;
|
||||
final Function(bool) exist;
|
||||
final bool isExist;
|
||||
final String name;
|
||||
final Function(String) val;
|
||||
const CustomTextFormField({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.entries,
|
||||
required this.context,
|
||||
required this.exist,
|
||||
required this.isExist,
|
||||
this.name = "",
|
||||
required this.val,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
autofocus: true,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.text,
|
||||
onChanged: (value) {
|
||||
if (name != controller.text) {
|
||||
exist(entries
|
||||
.where((element) => element.name == controller.text)
|
||||
.toList()
|
||||
.isNotEmpty);
|
||||
}
|
||||
val(value);
|
||||
},
|
||||
onFieldSubmitted: (s) {},
|
||||
decoration: InputDecoration(
|
||||
helperText: isExist == true
|
||||
? "A category with this name already exist!"
|
||||
: "*required",
|
||||
helperStyle: TextStyle(color: isExist == true ? Colors.red : null),
|
||||
isDense: true,
|
||||
label: Text("Name",
|
||||
style: TextStyle(color: isExist == true ? Colors.red : null)),
|
||||
filled: true,
|
||||
fillColor: Colors.transparent,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: isExist == true
|
||||
? Colors.red
|
||||
: Theme.of(context).primaryColor)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: isExist == true
|
||||
? Colors.red
|
||||
: Theme.of(context).primaryColor)),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: isExist == true
|
||||
? Colors.red
|
||||
: Theme.of(context).primaryColor))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ part of 'incognito_mode_state_provider.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$incognitoModeStateHash() =>
|
||||
r'614663075117c18594fda5884b79451ec77c3f1f';
|
||||
r'004cbf630f6431dcbaf87f4ac5dca0e2c96e689e';
|
||||
|
||||
/// See also [IncognitoModeState].
|
||||
@ProviderFor(IncognitoModeState)
|
||||
|
|
|
|||
|
|
@ -42,10 +42,10 @@ class _MangaImageCardWidgetState extends ConsumerState<MangaImageCardWidget> {
|
|||
link: widget.getMangaDetailModel!.url,
|
||||
source: widget.getMangaDetailModel!.source,
|
||||
lang: widget.lang,
|
||||
dateAdded: DateTime.now().microsecondsSinceEpoch,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
dateAdded: null,
|
||||
lastUpdate: null,
|
||||
chapters: widget.getMangaDetailModel!.chapters,
|
||||
category: null,
|
||||
categories: [],
|
||||
lastRead: '');
|
||||
if (mounted) {
|
||||
context.push('/manga-reader/detail', extra: modelManga);
|
||||
|
|
|
|||
|
|
@ -881,6 +881,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
random_string:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: random_string
|
||||
sha256: "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ dependencies:
|
|||
flutter_cache_manager: ^3.3.0
|
||||
draggable_menu: ^0.3.0
|
||||
fast_cached_network_image: ^1.2.0
|
||||
random_string: ^2.3.1
|
||||
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
|
|
|
|||
Loading…
Reference in a new issue