mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-03-11 17:25:32 +00:00
Extract reusable Select Bar and Button widgets
Previously, the same select bar and button styles were defined in both `library_screen.dart` and `manga_detail_view.dart`, resulting in repeated code. This commit extracts the select bar and its buttons into reusable widgets to reduce duplication and improve readability and maintainability.
This commit is contained in:
parent
ae1d158264
commit
c2bae6d17b
3 changed files with 371 additions and 478 deletions
|
|
@ -22,6 +22,7 @@ import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_pro
|
|||
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/widgets/bottom_select_bar.dart';
|
||||
import 'package:mangayomi/modules/widgets/category_selection_dialog.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart';
|
||||
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
|
||||
|
|
@ -554,161 +555,85 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
return const ProgressCenter();
|
||||
},
|
||||
),
|
||||
bottomNavigationBar: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
final color = Theme.of(context).textTheme.bodyLarge!.color!;
|
||||
bottomNavigationBar: Builder(
|
||||
builder: (context) {
|
||||
final mangaIds = ref.watch(mangasListStateProvider);
|
||||
return AnimatedContainer(
|
||||
curve: Curves.easeIn,
|
||||
decoration: BoxDecoration(
|
||||
color: context.primaryColor.withValues(alpha: 0.2),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
final color = Theme.of(context).textTheme.bodyLarge!.color!;
|
||||
return BottomSelectBar(
|
||||
isVisible: ref.watch(isLongPressedMangaStateProvider),
|
||||
actions: [
|
||||
BottomSelectButton(
|
||||
icon: Icon(Icons.label_outline_rounded, color: color),
|
||||
onPressed: () {
|
||||
final mangaIdsList = ref.watch(mangasListStateProvider);
|
||||
final List<Manga> bulkMangas = mangaIdsList
|
||||
.map((id) => isar.mangas.getSync(id)!)
|
||||
.toList();
|
||||
showCategorySelectionDialog(
|
||||
context: context,
|
||||
ref: ref,
|
||||
itemType: widget.itemType,
|
||||
bulkMangas: bulkMangas,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
duration: const Duration(milliseconds: 100),
|
||||
height: isLongPressed ? 70 : 0,
|
||||
width: context.width(1),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
shadowColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
final mangaIdsList = ref.watch(
|
||||
mangasListStateProvider,
|
||||
);
|
||||
final List<Manga> bulkMangas = mangaIdsList
|
||||
.map((id) => isar.mangas.getSync(id)!)
|
||||
.toList();
|
||||
showCategorySelectionDialog(
|
||||
context: context,
|
||||
ref: ref,
|
||||
itemType: widget.itemType,
|
||||
bulkMangas: bulkMangas,
|
||||
);
|
||||
},
|
||||
child: Icon(
|
||||
Icons.label_outline_rounded,
|
||||
color: color,
|
||||
),
|
||||
BottomSelectButton(
|
||||
icon: Icon(Icons.done_all_sharp, color: color),
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
mangasSetIsReadStateProvider(
|
||||
mangaIds: mangaIds,
|
||||
markAsRead: true,
|
||||
).notifier,
|
||||
)
|
||||
.set();
|
||||
ref.invalidate(
|
||||
getAllMangaWithoutCategoriesStreamProvider(
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
mangasSetIsReadStateProvider(
|
||||
mangaIds: mangaIds,
|
||||
markAsRead: true,
|
||||
).notifier,
|
||||
)
|
||||
.set();
|
||||
ref.invalidate(
|
||||
getAllMangaWithoutCategoriesStreamProvider(
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
);
|
||||
ref.invalidate(
|
||||
getAllMangaStreamProvider(
|
||||
categoryId: null,
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Icon(Icons.done_all_sharp, color: color),
|
||||
);
|
||||
ref.invalidate(
|
||||
getAllMangaStreamProvider(
|
||||
categoryId: null,
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
mangasSetIsReadStateProvider(
|
||||
mangaIds: mangaIds,
|
||||
markAsRead: false,
|
||||
).notifier,
|
||||
)
|
||||
.set();
|
||||
ref.invalidate(
|
||||
getAllMangaWithoutCategoriesStreamProvider(
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
);
|
||||
ref.invalidate(
|
||||
getAllMangaStreamProvider(
|
||||
categoryId: null,
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Icon(Icons.remove_done_sharp, color: color),
|
||||
);
|
||||
},
|
||||
),
|
||||
BottomSelectButton(
|
||||
icon: Icon(Icons.remove_done_sharp, color: color),
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
mangasSetIsReadStateProvider(
|
||||
mangaIds: mangaIds,
|
||||
markAsRead: false,
|
||||
).notifier,
|
||||
)
|
||||
.set();
|
||||
ref.invalidate(
|
||||
getAllMangaWithoutCategoriesStreamProvider(
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Expanded(
|
||||
// child: SizedBox(
|
||||
// height: 70,
|
||||
// child: ElevatedButton(
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// elevation: 0,
|
||||
// backgroundColor: Colors.transparent,
|
||||
// shadowColor: Colors.transparent,
|
||||
// ),
|
||||
// onPressed: () {},
|
||||
// child: Icon(
|
||||
// Icons.download_outlined,
|
||||
// color: color,
|
||||
// )),
|
||||
// ),
|
||||
// ),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
_deleteManga();
|
||||
},
|
||||
child: Icon(
|
||||
Icons.delete_outline_outlined,
|
||||
color: color,
|
||||
),
|
||||
);
|
||||
ref.invalidate(
|
||||
getAllMangaStreamProvider(
|
||||
categoryId: null,
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// BottomBarAction(
|
||||
// icon: Icon(Icons.download_outlined, color: color),
|
||||
// onPressed: () {}
|
||||
// ),
|
||||
BottomSelectButton(
|
||||
icon: Icon(Icons.delete_outline_outlined, color: color),
|
||||
onPressed: () => _deleteManga(),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import 'package:mangayomi/modules/manga/detail/widgets/tracker_widget.dart';
|
|||
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/pure_black_dark_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/track/widgets/track_listile.dart';
|
||||
import 'package:mangayomi/modules/widgets/bottom_select_bar.dart';
|
||||
import 'package:mangayomi/modules/widgets/category_selection_dialog.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_extended_image_provider.dart';
|
||||
|
|
@ -811,8 +812,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
bottomNavigationBar: Builder(
|
||||
builder: (context) {
|
||||
final chap = ref.watch(chaptersListStateProvider);
|
||||
bool getLength1 = chap.length == 1;
|
||||
bool checkFirstBookmarked =
|
||||
|
|
@ -821,340 +822,241 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
chap.isNotEmpty && chap.first.isRead! && getLength1;
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final color = Theme.of(context).textTheme.bodyLarge!.color!;
|
||||
return AnimatedContainer(
|
||||
curve: Curves.easeIn,
|
||||
decoration: BoxDecoration(
|
||||
color: context.primaryColor.withValues(alpha: 0.2),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
return BottomSelectBar(
|
||||
isVisible: isLongPressed,
|
||||
actions: [
|
||||
BottomSelectButton(
|
||||
icon: Icon(
|
||||
checkFirstBookmarked
|
||||
? Icons.bookmark_remove_outlined
|
||||
: Icons.bookmark_add_outlined,
|
||||
color: color,
|
||||
),
|
||||
onPressed: () {
|
||||
final chapters = ref.watch(chaptersListStateProvider);
|
||||
final List<Chapter> updatedChapters = [];
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
for (var chapter in chapters) {
|
||||
chapter.isBookmarked = !chapter.isBookmarked!;
|
||||
chapter.updatedAt = now;
|
||||
chapter.manga.value = widget.manga;
|
||||
updatedChapters.add(chapter);
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.chapters.putAllSync(updatedChapters);
|
||||
});
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref.read(chaptersListStateProvider.notifier).clear();
|
||||
},
|
||||
),
|
||||
),
|
||||
duration: const Duration(milliseconds: 100),
|
||||
height: isLongPressed ? 70 : 0,
|
||||
width: context.width(1),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
final chapters = ref.watch(
|
||||
chaptersListStateProvider,
|
||||
);
|
||||
final List<Chapter> updatedChapters = [];
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
for (var chapter in chapters) {
|
||||
chapter.isBookmarked = !chapter.isBookmarked!;
|
||||
chapter.updatedAt = now;
|
||||
chapter.manga.value = widget.manga;
|
||||
updatedChapters.add(chapter);
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.chapters.putAllSync(updatedChapters);
|
||||
});
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref
|
||||
.read(chaptersListStateProvider.notifier)
|
||||
.clear();
|
||||
},
|
||||
child: Icon(
|
||||
checkFirstBookmarked
|
||||
? Icons.bookmark_remove_outlined
|
||||
: Icons.bookmark_add_outlined,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
),
|
||||
BottomSelectButton(
|
||||
icon: Icon(
|
||||
checkReadBookmarked
|
||||
? Icons.remove_done_sharp
|
||||
: Icons.done_all_sharp,
|
||||
color: color,
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
final chapters = ref.watch(
|
||||
chaptersListStateProvider,
|
||||
);
|
||||
final List<Chapter> updatedChapters = [];
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
for (var chapter in chapters) {
|
||||
chapter.isRead = !chapter.isRead!;
|
||||
if (!chapter.isRead!) {
|
||||
chapter.lastPageRead = "1";
|
||||
}
|
||||
chapter.updatedAt = now;
|
||||
chapter.manga.value = widget.manga;
|
||||
updatedChapters.add(chapter);
|
||||
if (chapter.isRead!) {
|
||||
chapter.updateTrackChapterRead(ref);
|
||||
}
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.chapters.putAllSync(updatedChapters);
|
||||
isar.mangas.putSync(widget.manga!);
|
||||
});
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref
|
||||
.read(chaptersListStateProvider.notifier)
|
||||
.clear();
|
||||
},
|
||||
child: Icon(
|
||||
checkReadBookmarked
|
||||
? Icons.remove_done_sharp
|
||||
: Icons.done_all_sharp,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (getLength1)
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
int index = chapters.indexOf(chap.first);
|
||||
final List<Chapter> updatedChapters = [];
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
chapters[index + 1].updateTrackChapterRead(ref);
|
||||
for (
|
||||
var i = index + 1;
|
||||
i < chapters.length;
|
||||
i++
|
||||
) {
|
||||
final chapter = chapters[i];
|
||||
if (!chapter.isRead!) {
|
||||
chapter.isRead = true;
|
||||
chapter.lastPageRead = "1";
|
||||
chapter.updatedAt = now;
|
||||
chapter.manga.value = widget.manga;
|
||||
updatedChapters.add(chapter);
|
||||
}
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.chapters.putAllSync(updatedChapters);
|
||||
isar.mangas.putSync(widget.manga!);
|
||||
});
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref
|
||||
.read(chaptersListStateProvider.notifier)
|
||||
.clear();
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
Icon(Icons.done_outlined, color: color),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Icon(
|
||||
Icons.arrow_downward_outlined,
|
||||
size: 11,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!isLocalArchive)
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
for (var chapter in ref.watch(
|
||||
chaptersListStateProvider,
|
||||
)) {
|
||||
final entries = isar.downloads
|
||||
.filter()
|
||||
.idEqualTo(chapter.id)
|
||||
.findAllSync();
|
||||
if (entries.isEmpty ||
|
||||
!entries.first.isDownload!) {
|
||||
ref.read(
|
||||
addDownloadToQueueProvider(
|
||||
chapter: chapter,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
ref.watch(processDownloadsProvider());
|
||||
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref
|
||||
.read(chaptersListStateProvider.notifier)
|
||||
.clear();
|
||||
},
|
||||
child: Icon(Icons.download_outlined, color: color),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isLocalArchive)
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: () {
|
||||
final selectedChapters = ref.watch(
|
||||
chaptersListStateProvider,
|
||||
);
|
||||
final totalChapters =
|
||||
widget.manga!.chapters.length;
|
||||
final isLastChapters =
|
||||
selectedChapters.length == totalChapters;
|
||||
final isAnime = widget.itemType == ItemType.anime;
|
||||
final entryType = isAnime
|
||||
? l10n.episode
|
||||
: l10n.chapter;
|
||||
final pluralEntryType = isAnime
|
||||
? l10n.episodes
|
||||
: l10n.chapters;
|
||||
final mediaType = isAnime
|
||||
? l10n.anime
|
||||
: l10n.manga;
|
||||
final warningMessage = l10n
|
||||
.last_entry_delete_warning(
|
||||
totalChapters,
|
||||
entryType,
|
||||
pluralEntryType,
|
||||
mediaType,
|
||||
);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(l10n.delete_chapters),
|
||||
content: isLastChapters
|
||||
? Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: Colors.orange,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
warningMessage,
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.cancel),
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
final navigator = Navigator.of(
|
||||
context,
|
||||
);
|
||||
await isar.writeTxn(() async {
|
||||
final idsToDelete =
|
||||
selectedChapters
|
||||
.map((c) => c.id!)
|
||||
.toList();
|
||||
await isar.chapters.deleteAll(
|
||||
idsToDelete,
|
||||
);
|
||||
});
|
||||
if (!mounted) return;
|
||||
ref
|
||||
.read(
|
||||
isLongPressedStateProvider
|
||||
.notifier,
|
||||
)
|
||||
.update(false);
|
||||
ref
|
||||
.read(
|
||||
chaptersListStateProvider
|
||||
.notifier,
|
||||
)
|
||||
.clear();
|
||||
navigator.pop();
|
||||
if (isLastChapters) {
|
||||
navigator.pop();
|
||||
Future.delayed(
|
||||
const Duration(
|
||||
milliseconds: 350,
|
||||
),
|
||||
() {
|
||||
isar.writeTxn(
|
||||
() => isar.mangas.delete(
|
||||
widget.manga!.id!,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(l10n.delete),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
onPressed: () {
|
||||
final chapters = ref.watch(chaptersListStateProvider);
|
||||
final List<Chapter> updatedChapters = [];
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
for (var chapter in chapters) {
|
||||
chapter.isRead = !chapter.isRead!;
|
||||
if (!chapter.isRead!) {
|
||||
chapter.lastPageRead = "1";
|
||||
}
|
||||
chapter.updatedAt = now;
|
||||
chapter.manga.value = widget.manga;
|
||||
updatedChapters.add(chapter);
|
||||
if (chapter.isRead!) {
|
||||
chapter.updateTrackChapterRead(ref);
|
||||
}
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.chapters.putAllSync(updatedChapters);
|
||||
isar.mangas.putSync(widget.manga!);
|
||||
});
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref.read(chaptersListStateProvider.notifier).clear();
|
||||
},
|
||||
),
|
||||
if (getLength1)
|
||||
BottomSelectButton(
|
||||
icon: Stack(
|
||||
children: [
|
||||
Icon(Icons.done_outlined, color: color),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Icon(
|
||||
Icons.delete_outline_outlined,
|
||||
Icons.arrow_downward_outlined,
|
||||
size: 11,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
int index = chapters.indexOf(chap.first);
|
||||
final List<Chapter> updatedChapters = [];
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
chapters[index + 1].updateTrackChapterRead(ref);
|
||||
for (var i = index + 1; i < chapters.length; i++) {
|
||||
final chapter = chapters[i];
|
||||
if (!chapter.isRead!) {
|
||||
chapter.isRead = true;
|
||||
chapter.lastPageRead = "1";
|
||||
chapter.updatedAt = now;
|
||||
chapter.manga.value = widget.manga;
|
||||
updatedChapters.add(chapter);
|
||||
}
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.chapters.putAllSync(updatedChapters);
|
||||
isar.mangas.putSync(widget.manga!);
|
||||
});
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref.read(chaptersListStateProvider.notifier).clear();
|
||||
},
|
||||
),
|
||||
if (!isLocalArchive)
|
||||
BottomSelectButton(
|
||||
icon: Icon(Icons.download_outlined, color: color),
|
||||
onPressed: () {
|
||||
for (var chapter in ref.watch(
|
||||
chaptersListStateProvider,
|
||||
)) {
|
||||
final entries = isar.downloads
|
||||
.filter()
|
||||
.idEqualTo(chapter.id)
|
||||
.findAllSync();
|
||||
if (entries.isEmpty || !entries.first.isDownload!) {
|
||||
ref.read(
|
||||
addDownloadToQueueProvider(chapter: chapter),
|
||||
);
|
||||
}
|
||||
}
|
||||
ref.watch(processDownloadsProvider());
|
||||
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref.read(chaptersListStateProvider.notifier).clear();
|
||||
},
|
||||
),
|
||||
if (isLocalArchive)
|
||||
BottomSelectButton(
|
||||
icon: Icon(Icons.delete_outline_outlined, color: color),
|
||||
onPressed: () {
|
||||
final selectedChapters = ref.watch(
|
||||
chaptersListStateProvider,
|
||||
);
|
||||
final totalChapters = widget.manga!.chapters.length;
|
||||
final isLastChapters =
|
||||
selectedChapters.length == totalChapters;
|
||||
final isAnime = widget.itemType == ItemType.anime;
|
||||
final entryType = isAnime ? l10n.episode : l10n.chapter;
|
||||
final pluralEntryType = isAnime
|
||||
? l10n.episodes
|
||||
: l10n.chapters;
|
||||
final mediaType = isAnime ? l10n.anime : l10n.manga;
|
||||
final warningMessage = l10n.last_entry_delete_warning(
|
||||
totalChapters,
|
||||
entryType,
|
||||
pluralEntryType,
|
||||
mediaType,
|
||||
);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(l10n.delete_chapters),
|
||||
content: isLastChapters
|
||||
? Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: Colors.orange,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
warningMessage,
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.cancel),
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
final navigator = Navigator.of(context);
|
||||
await isar.writeTxn(() async {
|
||||
final idsToDelete = selectedChapters
|
||||
.map((c) => c.id!)
|
||||
.toList();
|
||||
await isar.chapters.deleteAll(
|
||||
idsToDelete,
|
||||
);
|
||||
});
|
||||
if (!mounted) return;
|
||||
ref
|
||||
.read(
|
||||
isLongPressedStateProvider
|
||||
.notifier,
|
||||
)
|
||||
.update(false);
|
||||
ref
|
||||
.read(
|
||||
chaptersListStateProvider
|
||||
.notifier,
|
||||
)
|
||||
.clear();
|
||||
navigator.pop();
|
||||
if (isLastChapters) {
|
||||
navigator.pop();
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 350),
|
||||
() {
|
||||
isar.writeTxn(
|
||||
() => isar.mangas.delete(
|
||||
widget.manga!.id!,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(l10n.delete),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
|||
66
lib/modules/widgets/bottom_select_bar.dart
Normal file
66
lib/modules/widgets/bottom_select_bar.dart
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
|
||||
/// Bar, that appears at the bottom of the screen when long-pressing (selecting)
|
||||
/// a Manga/Anime/Novel or Chapter/Episode
|
||||
class BottomSelectBar extends StatelessWidget {
|
||||
final bool isVisible;
|
||||
final List<BottomSelectButton> actions;
|
||||
|
||||
const BottomSelectBar({
|
||||
super.key,
|
||||
required this.isVisible,
|
||||
required this.actions,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedContainer(
|
||||
curve: Curves.easeIn,
|
||||
decoration: BoxDecoration(
|
||||
color: context.primaryColor.withValues(alpha: 0.2),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
duration: const Duration(milliseconds: 100),
|
||||
height: isVisible ? 70 : 0,
|
||||
width: context.width(1),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: actions,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Button for the BottomSelectBar
|
||||
class BottomSelectButton extends StatelessWidget {
|
||||
final Widget icon;
|
||||
final VoidCallback onPressed;
|
||||
|
||||
const BottomSelectButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
),
|
||||
onPressed: onPressed,
|
||||
child: icon,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue