mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-01-11 22:40:36 +00:00
Refactor an fix
This commit is contained in:
parent
251d7266f5
commit
b8fffca2b3
5 changed files with 914 additions and 336 deletions
|
|
@ -2,10 +2,13 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:mangayomi/utils/extensions/string_extensions.dart';
|
||||
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||
|
||||
Widget btnToShowChapterListDialog(
|
||||
|
|
@ -21,11 +24,70 @@ Widget btnToShowChapterListDialog(
|
|||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(title),
|
||||
content: SizedBox(
|
||||
width: context.width(0.8),
|
||||
child: ChapterListWidget(chapter: chapter),
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
elevation: 8,
|
||||
child: Container(
|
||||
width: context.width(0.85),
|
||||
constraints: BoxConstraints(maxHeight: context.height(0.8)),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
context.primaryColor.withValues(alpha: 0.05),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: context.primaryColor.withValues(alpha: 0.2),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.menu_book_rounded,
|
||||
color: context.primaryColor,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: Icon(
|
||||
Icons.close_rounded,
|
||||
color: context.primaryColor.withValues(alpha: 0.7),
|
||||
),
|
||||
tooltip: 'Fermer',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(child: ChapterListWidget(chapter: chapter)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
@ -79,22 +141,25 @@ class _ChapterListWidgetState extends State<ChapterListWidget> {
|
|||
Widget build(BuildContext context) {
|
||||
return Scrollbar(
|
||||
interactive: true,
|
||||
thickness: 12,
|
||||
thickness: 8,
|
||||
radius: const Radius.circular(10),
|
||||
controller: controller,
|
||||
child: CustomScrollView(
|
||||
controller: controller,
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
padding: const EdgeInsets.all(12),
|
||||
sliver: SuperSliverList.builder(
|
||||
itemCount: chapterList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final chapter = chapterList[index];
|
||||
final currentChap = chapter == chapterList[currentChapIndex];
|
||||
return ChapterListTile(
|
||||
chapter: chapter,
|
||||
currentChap: currentChap,
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: ChapterListTile(
|
||||
chapter: chapter,
|
||||
currentChap: currentChap,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
@ -123,86 +188,224 @@ class _ChapterListTileState extends State<ChapterListTile> {
|
|||
late bool isBookmarked = chapter.isBookmarked!;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: widget.currentChap
|
||||
? context.primaryColor.withValues(alpha: 0.3)
|
||||
: null,
|
||||
child: ListTile(
|
||||
textColor: chapter.isRead!
|
||||
? context.isLight
|
||||
? Colors.black.withValues(alpha: 0.4)
|
||||
: Colors.white.withValues(alpha: 0.3)
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.currentChap
|
||||
? context.primaryColor.withValues(alpha: 0.15)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: widget.currentChap
|
||||
? Border.all(
|
||||
color: context.primaryColor.withValues(alpha: 0.4),
|
||||
width: 1.5,
|
||||
)
|
||||
: null,
|
||||
selectedColor: chapter.isRead!
|
||||
? Colors.white.withValues(alpha: 0.3)
|
||||
: Colors.white,
|
||||
onTap: () async {
|
||||
if (!widget.currentChap) {
|
||||
Navigator.pop(context);
|
||||
pushReplacementMangaReaderView(context: context, chapter: chapter);
|
||||
}
|
||||
},
|
||||
title: Text(
|
||||
chapter.name!,
|
||||
style: const TextStyle(fontSize: 13),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Row(
|
||||
children: [
|
||||
if (!(chapter.manga.value!.isLocalArchive ?? false))
|
||||
Consumer(
|
||||
builder: (context, ref, child) => Text(
|
||||
chapter.dateUpload == null || chapter.dateUpload!.isEmpty
|
||||
? ""
|
||||
: dateFormat(
|
||||
chapter.dateUpload!,
|
||||
ref: ref,
|
||||
context: context,
|
||||
),
|
||||
style: const TextStyle(fontSize: 11),
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onTap: () async {
|
||||
if (!widget.currentChap) {
|
||||
Navigator.pop(context);
|
||||
pushReplacementMangaReaderView(
|
||||
context: context,
|
||||
chapter: chapter,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
// Chapter indicator
|
||||
Container(
|
||||
width: 4,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: chapter.isRead!
|
||||
? Colors.grey.withValues(alpha: 0.3)
|
||||
: context.primaryColor,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!chapter.isRead!)
|
||||
if (chapter.lastPageRead!.isNotEmpty &&
|
||||
chapter.lastPageRead != "1")
|
||||
if (chapter.scanlator != null && chapter.scanlator!.isNotEmpty)
|
||||
Row(
|
||||
const SizedBox(width: 12),
|
||||
// Chapter content
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(' • '),
|
||||
Text(
|
||||
chapter.scanlator!,
|
||||
chapter.name!,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontSize: 14,
|
||||
fontWeight: widget.currentChap
|
||||
? FontWeight.bold
|
||||
: FontWeight.w500,
|
||||
color: chapter.isRead!
|
||||
? context.isLight
|
||||
? Colors.black.withValues(alpha: 0.4)
|
||||
: Colors.white.withValues(alpha: 0.3)
|
||||
: Colors.white.withValues(alpha: 0.4)
|
||||
: null,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
if (!(chapter.manga.value!.isLocalArchive ?? false))
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final dateText =
|
||||
chapter.dateUpload == null ||
|
||||
chapter.dateUpload!.isEmpty
|
||||
? ""
|
||||
: dateFormat(
|
||||
chapter.dateUpload!,
|
||||
ref: ref,
|
||||
context: context,
|
||||
);
|
||||
return dateText.isNotEmpty
|
||||
? Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.access_time_rounded,
|
||||
size: 12,
|
||||
color: Colors.grey,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
dateText,
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
if (chapter.scanlator != null &&
|
||||
chapter.scanlator!.isNotEmpty)
|
||||
Row(
|
||||
children: [
|
||||
if (!(chapter.manga.value!.isLocalArchive ??
|
||||
false) &&
|
||||
(chapter.dateUpload != null &&
|
||||
chapter.dateUpload!.isNotEmpty))
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
),
|
||||
child: Text(
|
||||
'•',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
Icons.group_rounded,
|
||||
size: 12,
|
||||
color: Colors.grey,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Flexible(
|
||||
child: Text(
|
||||
chapter.scanlator!,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!chapter.isRead! &&
|
||||
chapter.lastPageRead!.isNotEmpty &&
|
||||
chapter.lastPageRead != "1")
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.bookmark_rounded,
|
||||
size: 12,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
chapter.manga.value!.itemType == ItemType.anime
|
||||
? context.l10n.episode_progress(
|
||||
Duration(
|
||||
milliseconds: int.parse(
|
||||
chapter.lastPageRead!,
|
||||
),
|
||||
).toString().substringBefore("."),
|
||||
)
|
||||
: context.l10n.page(
|
||||
chapter.manga.value!.itemType ==
|
||||
ItemType.manga
|
||||
? chapter.lastPageRead!
|
||||
: "${((double.tryParse(chapter.lastPageRead!) ?? 0) * 100).toStringAsFixed(0)} %",
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
trailing: Consumer(
|
||||
builder: (context, ref, child) => IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isBookmarked = !isBookmarked;
|
||||
});
|
||||
isar.writeTxnSync(
|
||||
() => {
|
||||
isar.chapters.putSync(
|
||||
chapter
|
||||
..isBookmarked = isBookmarked
|
||||
..updatedAt = DateTime.now().millisecondsSinceEpoch,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
// Bookmark button
|
||||
Consumer(
|
||||
builder: (context, ref, child) => Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isBookmarked = !isBookmarked;
|
||||
});
|
||||
isar.writeTxnSync(
|
||||
() => {
|
||||
isar.chapters.putSync(
|
||||
chapter
|
||||
..isBookmarked = isBookmarked
|
||||
..updatedAt =
|
||||
DateTime.now().millisecondsSinceEpoch,
|
||||
),
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Icon(
|
||||
isBookmarked
|
||||
? Icons.bookmark_rounded
|
||||
: Icons.bookmark_outline_rounded,
|
||||
color: isBookmarked
|
||||
? context.primaryColor
|
||||
: Colors.grey,
|
||||
size: 22,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
isBookmarked ? Icons.bookmark : Icons.bookmark_outline,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class AutoBackupLocationState extends _$AutoBackupLocationState {
|
|||
|
||||
@riverpod
|
||||
Future<void> checkAndBackup(Ref ref) async {
|
||||
ref.keepAlive();
|
||||
final settings = isar.settings.getSync(227);
|
||||
final backupFrequency = _duration(settings!.backupFrequency);
|
||||
if (backupFrequency == null || settings.startDatebackup == null) return;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
|
|||
fontSize = initFontSize;
|
||||
});
|
||||
});
|
||||
if (!isDesktop) SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
||||
discordRpc?.showChapterDetails(ref, chapter);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,22 +172,74 @@ class ReaderSettingsTab extends ConsumerWidget {
|
|||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.space_bar, size: 20),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: padding.toDouble(),
|
||||
min: 0,
|
||||
max: 50,
|
||||
divisions: 50,
|
||||
label: '$padding px',
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(novelReaderPaddingStateProvider.notifier)
|
||||
.set(value.toInt());
|
||||
},
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.space_bar_rounded,
|
||||
size: 22,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
trackHeight: 4,
|
||||
thumbShape: const RoundSliderThumbShape(
|
||||
enabledThumbRadius: 8,
|
||||
),
|
||||
overlayShape: const RoundSliderOverlayShape(
|
||||
overlayRadius: 16,
|
||||
),
|
||||
activeTrackColor: Theme.of(context).primaryColor,
|
||||
inactiveTrackColor: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.2),
|
||||
thumbColor: Theme.of(context).primaryColor,
|
||||
overlayColor: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.2),
|
||||
),
|
||||
child: Slider(
|
||||
value: padding.toDouble(),
|
||||
min: 0,
|
||||
max: 50,
|
||||
divisions: 50,
|
||||
label: '$padding px',
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(novelReaderPaddingStateProvider.notifier)
|
||||
.set(value.toInt());
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
'${padding}px',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text('${padding}px'),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
@ -202,22 +254,76 @@ class ReaderSettingsTab extends ConsumerWidget {
|
|||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.height, size: 20),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: lineHeight,
|
||||
min: 1.0,
|
||||
max: 3.0,
|
||||
divisions: 20,
|
||||
label: lineHeight.toStringAsFixed(1),
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(novelReaderLineHeightStateProvider.notifier)
|
||||
.set(value);
|
||||
},
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.height_rounded,
|
||||
size: 22,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
trackHeight: 4,
|
||||
thumbShape: const RoundSliderThumbShape(
|
||||
enabledThumbRadius: 8,
|
||||
),
|
||||
overlayShape: const RoundSliderOverlayShape(
|
||||
overlayRadius: 16,
|
||||
),
|
||||
activeTrackColor: Theme.of(context).primaryColor,
|
||||
inactiveTrackColor: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.2),
|
||||
thumbColor: Theme.of(context).primaryColor,
|
||||
overlayColor: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.2),
|
||||
),
|
||||
child: Slider(
|
||||
value: lineHeight,
|
||||
min: 1.0,
|
||||
max: 3.0,
|
||||
divisions: 20,
|
||||
label: lineHeight.toStringAsFixed(1),
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(
|
||||
novelReaderLineHeightStateProvider.notifier,
|
||||
)
|
||||
.set(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
lineHeight.toStringAsFixed(1),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(lineHeight.toStringAsFixed(1)),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
@ -328,19 +434,48 @@ class _SettingSection extends StatelessWidget {
|
|||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).textTheme.titleLarge?.color,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 4,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).textTheme.titleLarge?.color,
|
||||
letterSpacing: 0.3,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
|
||||
child: child,
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
Theme.of(context).primaryColor.withValues(alpha: 0.04),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).primaryColor.withValues(alpha: 0.1),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Padding(padding: const EdgeInsets.all(16), child: child),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
@ -402,38 +537,58 @@ class _ThemeButton extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: 70,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: _parseColor(backgroundColor),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Theme.of(context).primaryColor
|
||||
: Colors.grey.withValues(alpha: 0.3),
|
||||
width: isSelected ? 3 : 1,
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: 75,
|
||||
height: 70,
|
||||
decoration: BoxDecoration(
|
||||
color: _parseColor(backgroundColor),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Theme.of(context).primaryColor
|
||||
: Colors.grey.withValues(alpha: 0.3),
|
||||
width: isSelected ? 3 : 1.5,
|
||||
),
|
||||
boxShadow: isSelected
|
||||
? [
|
||||
BoxShadow(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.3),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Aa',
|
||||
style: TextStyle(
|
||||
color: _parseColor(textColor),
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Aa',
|
||||
style: TextStyle(
|
||||
color: _parseColor(textColor),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(color: _parseColor(textColor), fontSize: 10),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: _parseColor(textColor),
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -526,70 +681,127 @@ class _ColorPicker extends StatelessWidget {
|
|||
Color selectedColor,
|
||||
) {
|
||||
final isSelected = optionColor.toARGB32() == selectedColor.toARGB32();
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
onColorChanged(_colorToHex(optionColor));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: optionColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: isSelected ? Theme.of(context).primaryColor : Colors.grey,
|
||||
width: isSelected ? 3 : 1,
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
onColorChanged(_colorToHex(optionColor));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
color: optionColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: isSelected ? Theme.of(context).primaryColor : Colors.grey,
|
||||
width: isSelected ? 3 : 1.5,
|
||||
),
|
||||
boxShadow: isSelected
|
||||
? [
|
||||
BoxShadow(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).primaryColor.withValues(alpha: 0.4),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
child: isSelected
|
||||
? Icon(
|
||||
Icons.check_circle_rounded,
|
||||
size: 26,
|
||||
color: optionColor.computeLuminance() > 0.5
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: isSelected
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: optionColor.computeLuminance() > 0.5
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => _showColorPickerDialog(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey.withValues(alpha: 0.3)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: _parseColor(color),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: Colors.grey),
|
||||
),
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => _showColorPickerDialog(context),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Colors.grey.withValues(alpha: 0.3),
|
||||
width: 1.5,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontSize: 12)),
|
||||
Text(
|
||||
color,
|
||||
style: TextStyle(fontSize: 10, color: Colors.grey[600]),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
Theme.of(context).primaryColor.withValues(alpha: 0.03),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: _parseColor(color),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: Colors.grey.withValues(alpha: 0.5),
|
||||
width: 2,
|
||||
),
|
||||
],
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.arrow_drop_down),
|
||||
],
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
color,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey[600],
|
||||
fontFamily: 'monospace',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
Icons.palette_outlined,
|
||||
color: Theme.of(context).primaryColor.withValues(alpha: 0.7),
|
||||
size: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -609,29 +821,35 @@ class _AlignButton extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? Theme.of(context).primaryColor.withValues(alpha: 0.2)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? Theme.of(context).primaryColor.withValues(alpha: 0.15)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Theme.of(context).primaryColor
|
||||
: Colors.grey.withValues(alpha: 0.3),
|
||||
width: isSelected ? 2 : 1.5,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 22,
|
||||
color: isSelected
|
||||
? Theme.of(context).primaryColor
|
||||
: Colors.grey.withValues(alpha: 0.3),
|
||||
width: isSelected ? 2 : 1,
|
||||
: Theme.of(context).iconTheme.color,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: isSelected
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).iconTheme.color,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,136 +34,291 @@ void showCategorySelectionDialog({
|
|||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setState) => AlertDialog(
|
||||
title: Text(l10n.set_categories),
|
||||
content: SizedBox(
|
||||
width: context.width(0.8),
|
||||
child: StreamBuilder(
|
||||
stream: isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forItemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||
return Text(l10n.library_no_category_exist);
|
||||
}
|
||||
var entries = (snapshot.data!
|
||||
..sort((a, b) => (a.pos ?? 0).compareTo(b.pos ?? 0)));
|
||||
if (isFavorite || isBulk) {
|
||||
// When item is in library, hide hidden categories in list
|
||||
entries = entries.where((e) => !(e.hide ?? false)).toList();
|
||||
}
|
||||
if (entries.isEmpty) return Text(l10n.library_no_category_exist);
|
||||
return SuperListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: entries.length,
|
||||
itemBuilder: (context, index) {
|
||||
final category = entries[index];
|
||||
final isSelected = categoryIds.contains(category.id);
|
||||
if (!isBulk) {
|
||||
return ListTileChapterFilter(
|
||||
label: category.name!,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isSelected
|
||||
? categoryIds.remove(category.id)
|
||||
: categoryIds.add(category.id!);
|
||||
});
|
||||
},
|
||||
type: isSelected ? 1 : 0,
|
||||
);
|
||||
}
|
||||
return ListTileMangaCategory(
|
||||
category: category,
|
||||
categoryIds: categoryIds,
|
||||
mangasList: bulkMangas,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (isSelected) {
|
||||
categoryIds.remove(category.id);
|
||||
} else {
|
||||
categoryIds.add(category.id!);
|
||||
}
|
||||
});
|
||||
},
|
||||
res: (res) {
|
||||
if (res.isNotEmpty && !isSelected) {
|
||||
categoryIds.add(category.id!);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
builder: (context, setState) => Dialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
elevation: 8,
|
||||
child: Container(
|
||||
width: context.width(0.85),
|
||||
constraints: BoxConstraints(maxHeight: context.height(0.75)),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
context.primaryColor.withValues(alpha: 0.05),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(l10n.edit),
|
||||
onPressed: () {
|
||||
context.push(
|
||||
"/categories",
|
||||
extra: (
|
||||
true,
|
||||
itemType == ItemType.manga
|
||||
? 0
|
||||
: itemType == ItemType.anime
|
||||
? 1
|
||||
: 2,
|
||||
// Header
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: context.primaryColor.withValues(alpha: 0.2),
|
||||
width: 1,
|
||||
),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(l10n.cancel),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
TextButton(
|
||||
child: Text(l10n.ok),
|
||||
onPressed: () {
|
||||
isar.writeTxnSync(() {
|
||||
if (isBulk) {
|
||||
for (var manga in bulkMangas) {
|
||||
manga.categories = categoryIds;
|
||||
manga.updatedAt =
|
||||
DateTime.now().millisecondsSinceEpoch;
|
||||
isar.mangas.putSync(manga);
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: context.primaryColor.withValues(alpha: 0.15),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.category_rounded,
|
||||
color: context.primaryColor,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
l10n.set_categories,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: Icon(
|
||||
Icons.close_rounded,
|
||||
color: context.primaryColor.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Content
|
||||
Flexible(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: StreamBuilder(
|
||||
stream: isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forItemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.category_outlined,
|
||||
size: 64,
|
||||
color: Colors.grey.withValues(alpha: 0.5),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.library_no_category_exist,
|
||||
style: TextStyle(
|
||||
color: Colors.grey.withValues(alpha: 0.7),
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
var entries = (snapshot.data!
|
||||
..sort((a, b) => (a.pos ?? 0).compareTo(b.pos ?? 0)));
|
||||
if (isFavorite || isBulk) {
|
||||
// When item is in library, hide hidden categories in list
|
||||
entries = entries
|
||||
.where((e) => !(e.hide ?? false))
|
||||
.toList();
|
||||
}
|
||||
if (entries.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.category_outlined,
|
||||
size: 64,
|
||||
color: Colors.grey.withValues(alpha: 0.5),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.library_no_category_exist,
|
||||
style: TextStyle(
|
||||
color: Colors.grey.withValues(alpha: 0.7),
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return SuperListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: entries.length,
|
||||
itemBuilder: (context, index) {
|
||||
final category = entries[index];
|
||||
final isSelected = categoryIds.contains(category.id);
|
||||
if (!isBulk) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: ListTileChapterFilter(
|
||||
label: category.name!,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isSelected
|
||||
? categoryIds.remove(category.id)
|
||||
: categoryIds.add(category.id!);
|
||||
});
|
||||
},
|
||||
type: isSelected ? 1 : 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!isFavorite) {
|
||||
singleManga!.favorite = true;
|
||||
singleManga.dateAdded =
|
||||
DateTime.now().millisecondsSinceEpoch;
|
||||
}
|
||||
singleManga.categories = categoryIds;
|
||||
singleManga.updatedAt =
|
||||
DateTime.now().millisecondsSinceEpoch;
|
||||
isar.mangas.putSync(singleManga);
|
||||
}
|
||||
if (isBulk) {
|
||||
ref.read(mangasListStateProvider.notifier).clear();
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
}
|
||||
});
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 6),
|
||||
child: ListTileMangaCategory(
|
||||
category: category,
|
||||
categoryIds: categoryIds,
|
||||
mangasList: bulkMangas,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (isSelected) {
|
||||
categoryIds.remove(category.id);
|
||||
} else {
|
||||
categoryIds.add(category.id!);
|
||||
}
|
||||
});
|
||||
},
|
||||
res: (res) {
|
||||
if (res.isNotEmpty && !isSelected) {
|
||||
categoryIds.add(category.id!);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Actions
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: context.primaryColor.withValues(alpha: 0.1),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.edit_rounded, size: 18),
|
||||
label: Text(l10n.edit),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: context.primaryColor,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context.push(
|
||||
"/categories",
|
||||
extra: (
|
||||
true,
|
||||
itemType == ItemType.manga
|
||||
? 0
|
||||
: itemType == ItemType.anime
|
||||
? 1
|
||||
: 2,
|
||||
),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(l10n.cancel),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
FilledButton(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: context.primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 12,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
isar.writeTxnSync(() {
|
||||
if (isBulk) {
|
||||
for (var manga in bulkMangas) {
|
||||
manga.categories = categoryIds;
|
||||
manga.updatedAt =
|
||||
DateTime.now().millisecondsSinceEpoch;
|
||||
isar.mangas.putSync(manga);
|
||||
}
|
||||
} else {
|
||||
if (!isFavorite) {
|
||||
singleManga!.favorite = true;
|
||||
singleManga.dateAdded =
|
||||
DateTime.now().millisecondsSinceEpoch;
|
||||
}
|
||||
singleManga.categories = categoryIds;
|
||||
singleManga.updatedAt =
|
||||
DateTime.now().millisecondsSinceEpoch;
|
||||
isar.mangas.putSync(singleManga);
|
||||
}
|
||||
if (isBulk) {
|
||||
ref
|
||||
.read(mangasListStateProvider.notifier)
|
||||
.clear();
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
}
|
||||
});
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.ok),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue