Improve comic chapters.

This commit is contained in:
2025-02-20 13:08:55 +08:00
parent 2b3c7a8564
commit bd5d10e919
14 changed files with 324 additions and 97 deletions

View File

@@ -632,6 +632,7 @@ class _TabViewBodyState extends State<TabViewBody> {
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_controller = widget.controller ?? DefaultTabController.of(context); _controller = widget.controller ?? DefaultTabController.of(context);
_currentIndex = _controller.index;
_controller.addListener(updateIndex); _controller.addListener(updateIndex);
} }

View File

@@ -128,12 +128,7 @@ class ComicDetails with HistoryMixin {
final Map<String, List<String>> tags; final Map<String, List<String>> tags;
/// id-name /// id-name
final Map<String, String>? chapters; final ComicChapters? chapters;
/// key is group name.
/// When this field is not null, [chapters] will be a merged map of all groups.
/// Only available in some sources.
final Map<String, Map<String, String>>? groupedChapters;
final List<String>? thumbnails; final List<String>? thumbnails;
@@ -176,45 +171,13 @@ class ComicDetails with HistoryMixin {
return res; return res;
} }
static Map<String, String>? _getChapters(dynamic chapters) {
if (chapters == null) return null;
var result = <String, String>{};
if (chapters is Map) {
for (var entry in chapters.entries) {
var value = entry.value;
if (value is Map) {
result.addAll(Map.from(value));
} else {
result[entry.key.toString()] = value.toString();
}
}
}
return result;
}
static Map<String, Map<String, String>>? _getGroupedChapters(dynamic chapters) {
if (chapters == null) return null;
var result = <String, Map<String, String>>{};
if (chapters is Map) {
for (var entry in chapters.entries) {
var value = entry.value;
if (value is Map) {
result[entry.key.toString()] = Map.from(value);
}
}
}
if (result.isEmpty) return null;
return result;
}
ComicDetails.fromJson(Map<String, dynamic> json) ComicDetails.fromJson(Map<String, dynamic> json)
: title = json["title"], : title = json["title"],
subTitle = json["subtitle"], subTitle = json["subtitle"],
cover = json["cover"], cover = json["cover"],
description = json["description"], description = json["description"],
tags = _generateMap(json["tags"]), tags = _generateMap(json["tags"]),
chapters = _getChapters(json["chapters"]), chapters = ComicChapters.fromJsonOrNull(json["chapters"]),
groupedChapters = _getGroupedChapters(json["chapters"]),
sourceKey = json["sourceKey"], sourceKey = json["sourceKey"],
comicId = json["comicId"], comicId = json["comicId"],
thumbnails = ListOrNull.from(json["thumbnails"]), thumbnails = ListOrNull.from(json["thumbnails"]),
@@ -342,3 +305,122 @@ class ArchiveInfo {
description = json["description"], description = json["description"],
id = json["id"]; id = json["id"];
} }
class ComicChapters {
final Map<String, String>? _chapters;
final Map<String, Map<String, String>>? _groupedChapters;
/// Create a ComicChapters object with a flat map
const ComicChapters(Map<String, String> this._chapters)
: _groupedChapters = null;
/// Create a ComicChapters object with a grouped map
const ComicChapters.grouped(
Map<String, Map<String, String>> this._groupedChapters)
: _chapters = null;
factory ComicChapters.fromJson(dynamic json) {
if (json is! Map) throw ArgumentError("Invalid json type");
var chapters = <String, String>{};
var groupedChapters = <String, Map<String, String>>{};
for (var entry in json.entries) {
var key = entry.key;
var value = entry.value;
if (key is! String) throw ArgumentError("Invalid key type");
if (value is Map) {
groupedChapters[key] = Map.from(value);
} else {
chapters[key] = value.toString();
}
}
if (chapters.isNotEmpty) {
return ComicChapters(chapters);
} else {
return ComicChapters.grouped(groupedChapters);
}
}
static fromJsonOrNull(dynamic json) {
if (json == null) return null;
return ComicChapters.fromJson(json);
}
Map<String, dynamic> toJson() {
if (_chapters != null) {
return _chapters;
} else {
return _groupedChapters!;
}
}
/// Whether the chapters are grouped
bool get isGrouped => _groupedChapters != null;
/// All group names
Iterable<String> get groups => _groupedChapters?.keys ?? [];
/// All chapters.
/// If the chapters are grouped, all groups will be merged.
Map<String, String> get allChapters {
if (_chapters != null) return _chapters;
var res = <String, String>{};
for (var entry in _groupedChapters!.values) {
res.addAll(entry);
}
return res;
}
/// Get a group of chapters by name
Map<String, String> getGroup(String group) {
return _groupedChapters![group] ?? {};
}
/// Get a group of chapters by index
Map<String, String> getGroupByIndex(int index) {
return _groupedChapters!.values.elementAt(index);
}
/// Get a chapter by index
int get length {
return isGrouped
? _groupedChapters!.values.map((e) => e.length).reduce((a, b) => a + b)
: _chapters!.length;
}
/// Get the number of groups
int get groupCount => _groupedChapters?.length ?? 0;
/// Iterate all chapter ids
Iterable<String> get ids sync* {
if (isGrouped) {
for (var entry in _groupedChapters!.values) {
yield* entry.keys;
}
} else {
yield* _chapters!.keys;
}
}
/// Iterate all chapter titles
Iterable<String> get titles sync* {
if (isGrouped) {
for (var entry in _groupedChapters!.values) {
yield* entry.values;
}
} else {
yield* _chapters!.values;
}
}
String? operator [](String key) {
if (isGrouped) {
for (var entry in _groupedChapters!.values) {
if (entry.containsKey(key)) return entry[key];
}
return null;
} else {
return _chapters![key];
}
}
}

View File

@@ -97,7 +97,7 @@ class ImageFavoritesProvider
if (localComic == null) { if (localComic == null) {
return null; return null;
} }
var epIndex = localComic.chapters?.keys.toList().indexOf(eid) ?? -1; var epIndex = localComic.chapters?.ids.toList().indexOf(eid) ?? -1;
if (epIndex == -1 && localComic.hasChapters) { if (epIndex == -1 && localComic.hasChapters) {
return null; return null;
} }

View File

@@ -9,7 +9,6 @@ import 'package:venera/foundation/favorites.dart';
import 'package:venera/foundation/log.dart'; import 'package:venera/foundation/log.dart';
import 'package:venera/network/download.dart'; import 'package:venera/network/download.dart';
import 'package:venera/pages/reader/reader.dart'; import 'package:venera/pages/reader/reader.dart';
import 'package:venera/utils/ext.dart';
import 'package:venera/utils/io.dart'; import 'package:venera/utils/io.dart';
import 'app.dart'; import 'app.dart';
@@ -34,7 +33,7 @@ class LocalComic with HistoryMixin implements Comic {
/// key: chapter id, value: chapter title /// key: chapter id, value: chapter title
/// ///
/// chapter id is the name of the directory in `LocalManager.path/$directory` /// chapter id is the name of the directory in `LocalManager.path/$directory`
final Map<String, String>? chapters; final ComicChapters? chapters;
bool get hasChapters => chapters != null; bool get hasChapters => chapters != null;
@@ -67,7 +66,7 @@ class LocalComic with HistoryMixin implements Comic {
subtitle = row[2] as String, subtitle = row[2] as String,
tags = List.from(jsonDecode(row[3] as String)), tags = List.from(jsonDecode(row[3] as String)),
directory = row[4] as String, directory = row[4] as String,
chapters = MapOrNull.from(jsonDecode(row[5] as String)), chapters = ComicChapters.fromJsonOrNull(jsonDecode(row[5] as String)),
cover = row[6] as String, cover = row[6] as String,
comicType = ComicType(row[7] as int), comicType = ComicType(row[7] as int),
downloadedChapters = List.from(jsonDecode(row[8] as String)), downloadedChapters = List.from(jsonDecode(row[8] as String)),
@@ -99,6 +98,7 @@ class LocalComic with HistoryMixin implements Comic {
"tags": tags, "tags": tags,
"description": description, "description": description,
"sourceKey": sourceKey, "sourceKey": sourceKey,
"chapters": chapters?.toJson(),
}; };
} }
@@ -391,7 +391,7 @@ class LocalManager with ChangeNotifier {
var directory = Directory(comic.baseDir); var directory = Directory(comic.baseDir);
if (comic.hasChapters) { if (comic.hasChapters) {
var cid = var cid =
ep is int ? comic.chapters!.keys.elementAt(ep - 1) : (ep as String); ep is int ? comic.chapters!.ids.elementAt(ep - 1) : (ep as String);
directory = Directory(FilePath.join(directory.path, cid)); directory = Directory(FilePath.join(directory.path, cid));
} }
var files = <File>[]; var files = <File>[];
@@ -425,7 +425,7 @@ class LocalManager with ChangeNotifier {
if (comic == null) return false; if (comic == null) return false;
if (comic.chapters == null || ep == null) return true; if (comic.chapters == null || ep == null) return true;
return comic.downloadedChapters return comic.downloadedChapters
.contains(comic.chapters!.keys.elementAt(ep - 1)); .contains(comic.chapters!.ids.elementAt(ep - 1));
} }
List<DownloadTask> downloadingTasks = []; List<DownloadTask> downloadingTasks = [];

View File

@@ -328,8 +328,9 @@ class ImagesDownloadTask extends DownloadTask with _TransferSpeedMixin {
_images = {}; _images = {};
_totalCount = 0; _totalCount = 0;
int cpCount = 0; int cpCount = 0;
int totalCpCount = chapters?.length ?? comic!.chapters!.length; int totalCpCount =
for (var i in comic!.chapters!.keys) { chapters?.length ?? comic!.chapters!.allChapters.length;
for (var i in comic!.chapters!.allChapters.keys) {
if (chapters != null && !chapters!.contains(i)) { if (chapters != null && !chapters!.contains(i)) {
continue; continue;
} }

View File

@@ -262,7 +262,7 @@ abstract mixin class _ComicPageActions {
if (localComic != null) { if (localComic != null) {
for (int i = 0; i < comic.chapters!.length; i++) { for (int i = 0; i < comic.chapters!.length; i++) {
if (localComic.downloadedChapters if (localComic.downloadedChapters
.contains(comic.chapters!.keys.elementAt(i))) { .contains(comic.chapters!.ids.elementAt(i))) {
downloaded.add(i); downloaded.add(i);
} }
} }
@@ -270,7 +270,7 @@ abstract mixin class _ComicPageActions {
await showSideBar( await showSideBar(
App.rootContext, App.rootContext,
_SelectDownloadChapter( _SelectDownloadChapter(
comic.chapters!.values.toList(), comic.chapters!.titles.toList(),
(v) => selected = v, (v) => selected = v,
downloaded, downloaded,
), ),
@@ -281,7 +281,7 @@ abstract mixin class _ComicPageActions {
comicId: comic.id, comicId: comic.id,
comic: comic, comic: comic,
chapters: selected!.map((i) { chapters: selected!.map((i) {
return comic.chapters!.keys.elementAt(i); return comic.chapters!.ids.elementAt(i);
}).toList(), }).toList(),
)); ));
} }

View File

@@ -33,7 +33,7 @@ class _NormalComicChaptersState extends State<_NormalComicChapters> {
late History? history; late History? history;
late Map<String, String> chapters; late ComicChapters chapters;
@override @override
void initState() { void initState() {
@@ -101,7 +101,7 @@ class _NormalComicChaptersState extends State<_NormalComicChapters> {
if (reverse) { if (reverse) {
i = chapters.length - i - 1; i = chapters.length - i - 1;
} }
var key = chapters.keys.elementAt(i); var key = chapters.ids.elementAt(i);
var value = chapters[key]!; var value = chapters[key]!;
bool visited = (history?.readEpisode ?? {}).contains(i + 1); bool visited = (history?.readEpisode ?? {}).contains(i + 1);
return Padding( return Padding(
@@ -182,7 +182,7 @@ class _GroupedComicChaptersState extends State<_GroupedComicChapters>
late History? history; late History? history;
late Map<String, Map<String, String>> chapters; late ComicChapters chapters;
late TabController tabController; late TabController tabController;
@@ -197,9 +197,9 @@ class _GroupedComicChaptersState extends State<_GroupedComicChapters>
@override @override
void didChangeDependencies() { void didChangeDependencies() {
state = context.findAncestorStateOfType<_ComicPageState>()!; state = context.findAncestorStateOfType<_ComicPageState>()!;
chapters = state.comic.groupedChapters!; chapters = state.comic.chapters!;
tabController = TabController( tabController = TabController(
length: chapters.keys.length, length: chapters.ids.length,
vsync: this, vsync: this,
); );
tabController.addListener(onTabChange); tabController.addListener(onTabChange);
@@ -226,7 +226,7 @@ class _GroupedComicChaptersState extends State<_GroupedComicChapters>
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SliverLayoutBuilder( return SliverLayoutBuilder(
builder: (context, constrains) { builder: (context, constrains) {
var group = chapters.values.elementAt(index); var group = chapters.getGroupByIndex(index);
int length = group.length; int length = group.length;
bool canShowAll = showAll; bool canShowAll = showAll;
if (!showAll) { if (!showAll) {
@@ -265,7 +265,7 @@ class _GroupedComicChaptersState extends State<_GroupedComicChapters>
child: AppTabBar( child: AppTabBar(
withUnderLine: false, withUnderLine: false,
controller: tabController, controller: tabController,
tabs: chapters.keys.map((e) => Tab(text: e)).toList(), tabs: chapters.groups.map((e) => Tab(text: e)).toList(),
), ),
), ),
SliverPadding(padding: const EdgeInsets.only(top: 8)), SliverPadding(padding: const EdgeInsets.only(top: 8)),
@@ -279,12 +279,12 @@ class _GroupedComicChaptersState extends State<_GroupedComicChapters>
var key = group.keys.elementAt(i); var key = group.keys.elementAt(i);
var value = group[key]!; var value = group[key]!;
var chapterIndex = 0; var chapterIndex = 0;
for (var j = 0; j < chapters.length; j++) { for (var j = 0; j < chapters.groupCount; j++) {
if (j == index) { if (j == index) {
chapterIndex += i; chapterIndex += i;
break; break;
} }
chapterIndex += chapters.values.elementAt(j).length; chapterIndex += chapters.getGroupByIndex(j).length;
} }
bool visited = bool visited =
(history?.readEpisode ?? {}).contains(chapterIndex + 1); (history?.readEpisode ?? {}).contains(chapterIndex + 1);

View File

@@ -386,7 +386,7 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
String text; String text;
if (haveChapter) { if (haveChapter) {
text = "Last Reading: @epName Page @page".tlParams({ text = "Last Reading: @epName Page @page".tlParams({
'epName': comic.chapters!.values.elementAt( 'epName': comic.chapters!.titles.elementAt(
math.min(ep - 1, comic.chapters!.length - 1)), math.min(ep - 1, comic.chapters!.length - 1)),
'page': page, 'page': page,
}); });
@@ -610,7 +610,7 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
} }
return _ComicChapters( return _ComicChapters(
history: history, history: history,
groupedMode: comic.groupedChapters != null, groupedMode: comic.chapters!.isGrouped,
); );
} }

View File

@@ -45,7 +45,7 @@ class _ReaderImagesState extends State<_ReaderImages> {
} else { } else {
var res = await reader.type.comicSource!.loadComicPages!( var res = await reader.type.comicSource!.loadComicPages!(
reader.widget.cid, reader.widget.cid,
reader.widget.chapters?.keys.elementAt(reader.chapter - 1), reader.widget.chapters?.ids.elementAt(reader.chapter - 1),
); );
if (res.error) { if (res.error) {
setState(() { setState(() {

View File

@@ -101,7 +101,7 @@ class ReaderProps {
final String name; final String name;
final Map<String, String>? chapters; final ComicChapters? chapters;
final History history; final History history;

View File

@@ -76,9 +76,7 @@ class Reader extends StatefulWidget {
final String name; final String name;
/// key: Chapter ID, value: Chapter Name final ComicChapters? chapters;
/// null if the comic is a gallery
final Map<String, String>? chapters;
/// Starts from 1, invalid values equal to 1 /// Starts from 1, invalid values equal to 1
final int? initialPage; final int? initialPage;
@@ -105,7 +103,7 @@ class _ReaderState extends State<Reader> with _ReaderLocation, _ReaderWindow {
String get cid => widget.cid; String get cid => widget.cid;
String get eid => widget.chapters?.keys.elementAt(chapter - 1) ?? '0'; String get eid => widget.chapters?.ids.elementAt(chapter - 1) ?? '0';
List<String>? images; List<String>? images;

View File

@@ -279,7 +279,7 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> {
List<String> tags = context.reader.widget.tags; List<String> tags = context.reader.widget.tags;
String author = context.reader.widget.author; String author = context.reader.widget.author;
var epName = context.reader.widget.chapters?.values var epName = context.reader.widget.chapters?.titles
.elementAtOrNull(context.reader.chapter - 1) ?? .elementAtOrNull(context.reader.chapter - 1) ??
"E${context.reader.chapter}"; "E${context.reader.chapter}";
var translatedTags = tags.map((e) => e.translateTagsToCN).toList(); var translatedTags = tags.map((e) => e.translateTagsToCN).toList();
@@ -561,7 +561,7 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> {
} }
Widget buildPageInfoText() { Widget buildPageInfoText() {
var epName = context.reader.widget.chapters?.values var epName = context.reader.widget.chapters?.titles
.elementAtOrNull(context.reader.chapter - 1) ?? .elementAtOrNull(context.reader.chapter - 1) ??
"E${context.reader.chapter}"; "E${context.reader.chapter}";
if (epName.length > 8) { if (epName.length > 8) {
@@ -614,7 +614,9 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> {
void openChapterDrawer() { void openChapterDrawer() {
showSideBar( showSideBar(
context, context,
_ChaptersView(context.reader), context.reader.widget.chapters!.isGrouped
? _GroupedChaptersView(context.reader)
: _ChaptersView(context.reader),
width: 400, width: 400,
); );
} }
@@ -1030,14 +1032,27 @@ class _ChaptersView extends StatefulWidget {
class _ChaptersViewState extends State<_ChaptersView> { class _ChaptersViewState extends State<_ChaptersView> {
bool desc = false; bool desc = false;
late final ScrollController _scrollController;
@override
void initState() {
super.initState();
int epIndex = widget.reader.chapter - 2;
_scrollController = ScrollController(
initialScrollOffset: (epIndex * 48.0 + 52).clamp(0, double.infinity),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chapters = widget.reader.widget.chapters!; var chapters = widget.reader.widget.chapters!;
var current = widget.reader.chapter - 1; var current = widget.reader.chapter - 1;
return Scaffold( return Scaffold(
body: SmoothCustomScrollView( body: SmoothCustomScrollView(
controller: _scrollController,
slivers: [ slivers: [
SliverAppbar( SliverAppbar(
style: AppbarStyle.shadow,
title: Text("Chapters".tl), title: Text("Chapters".tl),
actions: [ actions: [
Tooltip( Tooltip(
@@ -1063,26 +1078,35 @@ class _ChaptersViewState extends State<_ChaptersView> {
if (desc) { if (desc) {
index = chapters.length - 1 - index; index = chapters.length - 1 - index;
} }
var chapter = chapters.values.elementAt(index); var chapter = chapters.titles.elementAt(index);
return ListTile( return InkWell(
shape: Border(
left: BorderSide(
color: current == index
? context.colorScheme.primary
: Colors.transparent,
width: 4,
),
),
title: Text(
chapter,
style: current == index
? ts.withColor(context.colorScheme.primary).bold
: null,
),
onTap: () { onTap: () {
widget.reader.toChapter(index + 1); widget.reader.toChapter(index + 1);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Container(
height: 48,
padding: const EdgeInsets.only(left: 16),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: current == index
? context.colorScheme.primary
: Colors.transparent,
width: 2,
),
),
),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
chapter,
style: current == index
? ts.withColor(context.colorScheme.primary).bold.s16
: ts.s16,
),
),
),
); );
}, },
childCount: chapters.length, childCount: chapters.length,
@@ -1093,3 +1117,120 @@ class _ChaptersViewState extends State<_ChaptersView> {
); );
} }
} }
class _GroupedChaptersView extends StatefulWidget {
const _GroupedChaptersView(this.reader);
final _ReaderState reader;
@override
State<_GroupedChaptersView> createState() => _GroupedChaptersViewState();
}
class _GroupedChaptersViewState extends State<_GroupedChaptersView>
with SingleTickerProviderStateMixin {
ComicChapters get chapters => widget.reader.widget.chapters!;
late final TabController tabController;
late final ScrollController _scrollController;
late final initialGroupName;
@override
void initState() {
super.initState();
int index = 0;
int epIndex = widget.reader.chapter - 1;
while (epIndex >= 0) {
epIndex -= chapters.getGroupByIndex(index).length;
index++;
}
tabController = TabController(
length: chapters.groups.length,
vsync: this,
initialIndex: index - 1,
);
initialGroupName = chapters.groups.elementAt(index - 1);
var epIndexAtGroup = widget.reader.chapter - 1;
for (var i = 0; i < index-1; i++) {
epIndexAtGroup -= chapters.getGroupByIndex(i).length;
}
_scrollController = ScrollController(
initialScrollOffset: (epIndexAtGroup * 48.0).clamp(0, double.infinity),
);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Appbar(title: Text("Chapters".tl)),
AppTabBar(
controller: tabController,
tabs: chapters.groups.map((e) => Tab(text: e)).toList(),
),
Expanded(
child: TabViewBody(
controller: tabController,
children: chapters.groups.map(buildGroup).toList(),
),
),
],
);
}
Widget buildGroup(String groupName) {
var group = chapters.getGroup(groupName);
return SmoothCustomScrollView(
controller: initialGroupName == groupName ? _scrollController : null,
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
var name = group.values.elementAt(index);
var i = 0;
for (var g in chapters.groups) {
if (g == groupName) {
break;
}
i += chapters.getGroup(g).length;
}
i += index + 1;
return InkWell(
onTap: () {
widget.reader.toChapter(i);
context.pop();
},
child: Container(
height: 48,
padding: const EdgeInsets.only(left: 16),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: widget.reader.chapter == i
? context.colorScheme.primary
: Colors.transparent,
width: 2,
),
),
),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
name,
style: widget.reader.chapter == i
? ts.withColor(context.colorScheme.primary).bold.s16
: ts.s16,
),
),
),
);
},
childCount: group.length,
),
),
],
);
}
}

View File

@@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter_7zip/flutter_7zip.dart'; import 'package:flutter_7zip/flutter_7zip.dart';
import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/comic_type.dart'; import 'package:venera/foundation/comic_type.dart';
import 'package:venera/foundation/local.dart'; import 'package:venera/foundation/local.dart';
import 'package:venera/utils/ext.dart'; import 'package:venera/utils/ext.dart';
@@ -176,7 +177,7 @@ abstract class CBZ {
tags: metaData.tags, tags: metaData.tags,
comicType: ComicType.local, comicType: ComicType.local,
directory: dest.name, directory: dest.name,
chapters: cpMap, chapters: ComicChapters.fromJson(cpMap),
downloadedChapters: cpMap?.keys.toList() ?? [], downloadedChapters: cpMap?.keys.toList() ?? [],
cover: 'cover.${coverFile.extension}', cover: 'cover.${coverFile.extension}',
createdAt: DateTime.now(), createdAt: DateTime.now(),

View File

@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:venera/components/components.dart'; import 'package:venera/components/components.dart';
import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/comic_type.dart'; import 'package:venera/foundation/comic_type.dart';
import 'package:venera/foundation/favorites.dart'; import 'package:venera/foundation/favorites.dart';
import 'package:venera/foundation/local.dart'; import 'package:venera/foundation/local.dart';
@@ -262,7 +263,9 @@ class ImportComic {
subtitle: subtitle ?? '', subtitle: subtitle ?? '',
tags: tags ?? [], tags: tags ?? [],
directory: directory.path, directory: directory.path,
chapters: hasChapters ? Map.fromIterables(chapters, chapters) : null, chapters: hasChapters
? ComicChapters(Map.fromIterables(chapters, chapters))
: null,
cover: coverPath, cover: coverPath,
comicType: ComicType.local, comicType: ComicType.local,
downloadedChapters: chapters, downloadedChapters: chapters,