mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
436 lines
13 KiB
Dart
436 lines
13 KiB
Dart
part of 'comic_page.dart';
|
|
|
|
abstract mixin class _ComicPageActions {
|
|
void update();
|
|
|
|
ComicDetails get comic;
|
|
|
|
ComicSource get comicSource => ComicSource.find(comic.sourceKey)!;
|
|
|
|
History? get history;
|
|
|
|
bool isLiking = false;
|
|
|
|
bool isLiked = false;
|
|
|
|
void likeOrUnlike() async {
|
|
if (isLiking) return;
|
|
isLiking = true;
|
|
update();
|
|
var res = await comicSource.likeOrUnlikeComic!(comic.id, isLiked);
|
|
if (res.error) {
|
|
App.rootContext.showMessage(message: res.errorMessage!);
|
|
} else {
|
|
isLiked = !isLiked;
|
|
}
|
|
isLiking = false;
|
|
update();
|
|
}
|
|
|
|
/// whether the comic is added to local favorite
|
|
bool isAddToLocalFav = false;
|
|
|
|
/// whether the comic is favorite on the server
|
|
bool isFavorite = false;
|
|
|
|
FavoriteItem _toFavoriteItem() {
|
|
var tags = <String>[];
|
|
for (var e in comic.tags.entries) {
|
|
tags.addAll(e.value.map((tag) => '${e.key}:$tag'));
|
|
}
|
|
return FavoriteItem(
|
|
id: comic.id,
|
|
name: comic.title,
|
|
coverPath: comic.cover,
|
|
author: comic.subTitle ?? comic.uploader ?? '',
|
|
type: comic.comicType,
|
|
tags: tags,
|
|
);
|
|
}
|
|
|
|
void openFavPanel() {
|
|
showSideBar(
|
|
App.rootContext,
|
|
_FavoritePanel(
|
|
cid: comic.id,
|
|
type: comic.comicType,
|
|
isFavorite: isFavorite,
|
|
onFavorite: (local, network) {
|
|
isFavorite = network ?? isFavorite;
|
|
isAddToLocalFav = local ?? isAddToLocalFav;
|
|
update();
|
|
},
|
|
favoriteItem: _toFavoriteItem(),
|
|
updateTime: comic.findUpdateTime(),
|
|
),
|
|
);
|
|
}
|
|
|
|
void quickFavorite() {
|
|
var folder = appdata.settings['quickFavorite'];
|
|
if (folder is! String) {
|
|
return;
|
|
}
|
|
LocalFavoritesManager().addComic(
|
|
folder,
|
|
_toFavoriteItem(),
|
|
null,
|
|
comic.findUpdateTime(),
|
|
);
|
|
isAddToLocalFav = true;
|
|
update();
|
|
App.rootContext.showMessage(message: "Added".tl);
|
|
}
|
|
|
|
void share() {
|
|
var text = comic.title;
|
|
if (comic.url != null) {
|
|
text += '\n${comic.url}';
|
|
}
|
|
Share.shareText(text);
|
|
}
|
|
|
|
/// read the comic
|
|
///
|
|
/// [ep] the episode number, start from 1
|
|
///
|
|
/// [page] the page number, start from 1
|
|
void read([int? ep, int? page]) {
|
|
App.rootContext
|
|
.to(
|
|
() => Reader(
|
|
type: comic.comicType,
|
|
cid: comic.id,
|
|
name: comic.title,
|
|
chapters: comic.chapters,
|
|
initialChapter: ep,
|
|
initialPage: page,
|
|
history: history ?? History.fromModel(model: comic, ep: 0, page: 0),
|
|
author: comic.findAuthor() ?? '',
|
|
tags: comic.plainTags,
|
|
),
|
|
)
|
|
.then((_) {
|
|
onReadEnd();
|
|
});
|
|
}
|
|
|
|
void continueRead() {
|
|
var ep = history?.ep ?? 1;
|
|
var page = history?.page ?? 1;
|
|
read(ep, page);
|
|
}
|
|
|
|
void onReadEnd();
|
|
|
|
void download() async {
|
|
if (LocalManager().isDownloading(comic.id, comic.comicType)) {
|
|
App.rootContext.showMessage(message: "The comic is downloading".tl);
|
|
return;
|
|
}
|
|
if (comic.chapters == null &&
|
|
LocalManager().isDownloaded(comic.id, comic.comicType, 0)) {
|
|
App.rootContext.showMessage(message: "The comic is downloaded".tl);
|
|
return;
|
|
}
|
|
|
|
if (comicSource.archiveDownloader != null) {
|
|
bool useNormalDownload = false;
|
|
List<ArchiveInfo>? archives;
|
|
int selected = -1;
|
|
bool isLoading = false;
|
|
bool isGettingLink = false;
|
|
await showDialog(
|
|
context: App.rootContext,
|
|
builder: (context) {
|
|
return StatefulBuilder(
|
|
builder: (context, setState) {
|
|
return ContentDialog(
|
|
title: "Download".tl,
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
RadioListTile<int>(
|
|
value: -1,
|
|
groupValue: selected,
|
|
title: Text("Normal".tl),
|
|
onChanged: (v) {
|
|
setState(() {
|
|
selected = v!;
|
|
});
|
|
},
|
|
),
|
|
ExpansionTile(
|
|
title: Text("Archive".tl),
|
|
shape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.zero,
|
|
),
|
|
collapsedShape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.zero,
|
|
),
|
|
onExpansionChanged: (b) {
|
|
if (!isLoading && b && archives == null) {
|
|
isLoading = true;
|
|
comicSource.archiveDownloader!
|
|
.getArchives(comic.id)
|
|
.then((value) {
|
|
if (value.success) {
|
|
archives = value.data;
|
|
} else {
|
|
App.rootContext
|
|
.showMessage(message: value.errorMessage!);
|
|
}
|
|
setState(() {
|
|
isLoading = false;
|
|
});
|
|
});
|
|
}
|
|
},
|
|
children: [
|
|
if (archives == null)
|
|
const ListLoadingIndicator().toCenter()
|
|
else
|
|
for (int i = 0; i < archives!.length; i++)
|
|
RadioListTile<int>(
|
|
value: i,
|
|
groupValue: selected,
|
|
onChanged: (v) {
|
|
setState(() {
|
|
selected = v!;
|
|
});
|
|
},
|
|
title: Text(archives![i].title),
|
|
subtitle: Text(archives![i].description),
|
|
)
|
|
],
|
|
)
|
|
],
|
|
),
|
|
actions: [
|
|
Button.filled(
|
|
isLoading: isGettingLink,
|
|
onPressed: () async {
|
|
if (selected == -1) {
|
|
useNormalDownload = true;
|
|
context.pop();
|
|
return;
|
|
}
|
|
setState(() {
|
|
isGettingLink = true;
|
|
});
|
|
var res =
|
|
await comicSource.archiveDownloader!.getDownloadUrl(
|
|
comic.id,
|
|
archives![selected].id,
|
|
);
|
|
if (res.error) {
|
|
App.rootContext.showMessage(message: res.errorMessage!);
|
|
setState(() {
|
|
isGettingLink = false;
|
|
});
|
|
} else if (context.mounted) {
|
|
LocalManager()
|
|
.addTask(ArchiveDownloadTask(res.data, comic));
|
|
App.rootContext
|
|
.showMessage(message: "Download started".tl);
|
|
context.pop();
|
|
}
|
|
},
|
|
child: Text("Confirm".tl),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
},
|
|
);
|
|
if (!useNormalDownload) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (comic.chapters == null) {
|
|
LocalManager().addTask(ImagesDownloadTask(
|
|
source: comicSource,
|
|
comicId: comic.id,
|
|
comic: comic,
|
|
));
|
|
} else {
|
|
List<int>? selected;
|
|
var downloaded = <int>[];
|
|
var localComic = LocalManager().find(comic.id, comic.comicType);
|
|
if (localComic != null) {
|
|
for (int i = 0; i < comic.chapters!.length; i++) {
|
|
if (localComic.downloadedChapters
|
|
.contains(comic.chapters!.ids.elementAt(i))) {
|
|
downloaded.add(i);
|
|
}
|
|
}
|
|
}
|
|
await showSideBar(
|
|
App.rootContext,
|
|
_SelectDownloadChapter(
|
|
comic.chapters!.titles.toList(),
|
|
(v) => selected = v,
|
|
downloaded,
|
|
),
|
|
);
|
|
if (selected == null) return;
|
|
LocalManager().addTask(ImagesDownloadTask(
|
|
source: comicSource,
|
|
comicId: comic.id,
|
|
comic: comic,
|
|
chapters: selected!.map((i) {
|
|
return comic.chapters!.ids.elementAt(i);
|
|
}).toList(),
|
|
));
|
|
}
|
|
App.rootContext.showMessage(message: "Download started".tl);
|
|
update();
|
|
}
|
|
|
|
void onTapTag(String tag, String namespace) {
|
|
var config = comicSource.handleClickTagEvent?.call(namespace, tag) ??
|
|
{
|
|
'action': 'search',
|
|
'keyword': tag,
|
|
};
|
|
var context = App.mainNavigatorKey!.currentContext!;
|
|
if (config['action'] == 'search') {
|
|
context.to(() => SearchResultPage(
|
|
text: config['keyword'] ?? '',
|
|
sourceKey: comicSource.key,
|
|
options: const [],
|
|
));
|
|
} else if (config['action'] == 'category') {
|
|
context.to(
|
|
() => CategoryComicsPage(
|
|
category: config['keyword'] ?? '',
|
|
categoryKey: comicSource.categoryData!.key,
|
|
param: config['param'],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void showMoreActions() {
|
|
var context = App.rootContext;
|
|
showMenuX(
|
|
context,
|
|
Offset(
|
|
context.width - 16,
|
|
context.padding.top,
|
|
),
|
|
[
|
|
MenuEntry(
|
|
icon: Icons.copy,
|
|
text: "Copy Title".tl,
|
|
onClick: () {
|
|
Clipboard.setData(ClipboardData(text: comic.title));
|
|
context.showMessage(message: "Copied".tl);
|
|
},
|
|
),
|
|
MenuEntry(
|
|
icon: Icons.copy_rounded,
|
|
text: "Copy ID".tl,
|
|
onClick: () {
|
|
Clipboard.setData(ClipboardData(text: comic.id));
|
|
context.showMessage(message: "Copied".tl);
|
|
},
|
|
),
|
|
if (comic.url != null)
|
|
MenuEntry(
|
|
icon: Icons.link,
|
|
text: "Copy URL".tl,
|
|
onClick: () {
|
|
Clipboard.setData(ClipboardData(text: comic.url!));
|
|
context.showMessage(message: "Copied".tl);
|
|
},
|
|
),
|
|
if (comic.url != null)
|
|
MenuEntry(
|
|
icon: Icons.open_in_browser,
|
|
text: "Open in Browser".tl,
|
|
onClick: () {
|
|
launchUrlString(comic.url!);
|
|
},
|
|
),
|
|
]);
|
|
}
|
|
|
|
void showComments() {
|
|
showSideBar(
|
|
App.rootContext,
|
|
CommentsPage(
|
|
data: comic,
|
|
source: comicSource,
|
|
),
|
|
);
|
|
}
|
|
|
|
void starRating() {
|
|
if (!comicSource.isLogged) {
|
|
return;
|
|
}
|
|
var rating = 0.0;
|
|
var isLoading = false;
|
|
showDialog(
|
|
context: App.rootContext,
|
|
builder: (dialogContext) => StatefulBuilder(
|
|
builder: (context, setState) => SimpleDialog(
|
|
title: const Text("Rating"),
|
|
alignment: Alignment.center,
|
|
children: [
|
|
SizedBox(
|
|
height: 100,
|
|
child: Center(
|
|
child: SizedBox(
|
|
width: 210,
|
|
child: Column(
|
|
children: [
|
|
const SizedBox(
|
|
height: 10,
|
|
),
|
|
RatingWidget(
|
|
padding: 2,
|
|
onRatingUpdate: (value) => rating = value,
|
|
value: 1,
|
|
selectable: true,
|
|
size: 40,
|
|
),
|
|
const Spacer(),
|
|
Button.filled(
|
|
isLoading: isLoading,
|
|
onPressed: () {
|
|
setState(() {
|
|
isLoading = true;
|
|
});
|
|
comicSource.starRatingFunc!(comic.id, rating.round())
|
|
.then((value) {
|
|
if (value.success) {
|
|
App.rootContext
|
|
.showMessage(message: "Success".tl);
|
|
Navigator.of(dialogContext).pop();
|
|
} else {
|
|
App.rootContext
|
|
.showMessage(message: value.errorMessage!);
|
|
setState(() {
|
|
isLoading = false;
|
|
});
|
|
}
|
|
});
|
|
},
|
|
child: Text("Submit".tl),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|