like a comic

This commit is contained in:
nyne
2024-10-05 08:56:06 +08:00
parent 07dbf6e6af
commit 771feeeaa8
4 changed files with 65 additions and 14 deletions

View File

@@ -95,6 +95,8 @@ abstract class LoadingState<T extends StatefulWidget, S extends Object>
Future<Res<S>> loadData(); Future<Res<S>> loadData();
void onDataLoaded() {}
Widget buildContent(BuildContext context, S data); Widget buildContent(BuildContext context, S data);
Widget? buildFrame(BuildContext context, Widget child) => null; Widget? buildFrame(BuildContext context, Widget child) => null;
@@ -118,6 +120,7 @@ abstract class LoadingState<T extends StatefulWidget, S extends Object>
isLoading = false; isLoading = false;
data = value.data; data = value.data;
}); });
onDataLoaded();
} else { } else {
setState(() { setState(() {
isLoading = false; isLoading = false;

View File

@@ -3,7 +3,6 @@ library comic_source;
import 'dart:async'; import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@@ -45,6 +44,8 @@ typedef GetThumbnailLoadingConfigFunc = Map<String, dynamic> Function(
typedef ComicThumbnailLoader = Future<Res<List<String>>> Function(String comicId, String? next); typedef ComicThumbnailLoader = Future<Res<List<String>>> Function(String comicId, String? next);
typedef LikeOrUnlikeComicFunc = Future<Res<bool>> Function(String comicId, bool isLiking);
class ComicSource { class ComicSource {
static final List<ComicSource> _sources = []; static final List<ComicSource> _sources = [];
@@ -171,6 +172,8 @@ class ComicSource {
final RegExp? idMatcher; final RegExp? idMatcher;
final LikeOrUnlikeComicFunc? likeOrUnlikeComic;
Future<void> loadData() async { Future<void> loadData() async {
var file = File("${App.dataPath}/comic_source/$key.data"); var file = File("${App.dataPath}/comic_source/$key.data");
if (await file.exists()) { if (await file.exists()) {
@@ -229,7 +232,8 @@ class ComicSource {
this.url, this.url,
this.version, this.version,
this.commentsLoader, this.commentsLoader,
this.sendCommentFunc) this.sendCommentFunc,
this.likeOrUnlikeComic)
: idMatcher = null; : idMatcher = null;
ComicSource.unknown(this.key) ComicSource.unknown(this.key)
@@ -252,7 +256,8 @@ class ComicSource {
version = "", version = "",
commentsLoader = null, commentsLoader = null,
sendCommentFunc = null, sendCommentFunc = null,
idMatcher = null; idMatcher = null,
likeOrUnlikeComic = null;
} }
class AccountConfig { class AccountConfig {

View File

@@ -136,6 +136,7 @@ class ComicSourceParser {
final favoriteData = _loadFavoriteData(); final favoriteData = _loadFavoriteData();
final commentsLoader = _parseCommentsLoader(); final commentsLoader = _parseCommentsLoader();
final sendCommentFunc = _parseSendCommentFunc(); final sendCommentFunc = _parseSendCommentFunc();
final likeFunc = _parseLikeFunc();
var source = ComicSource( var source = ComicSource(
_name!, _name!,
@@ -158,6 +159,7 @@ class ComicSourceParser {
version ?? "1.0.0", version ?? "1.0.0",
commentsLoader, commentsLoader,
sendCommentFunc, sendCommentFunc,
likeFunc,
); );
await source.loadData(); await source.loadData();
@@ -654,4 +656,21 @@ class ComicSourceParser {
} }
}; };
} }
LikeOrUnlikeComicFunc? _parseLikeFunc() {
if (!_checkExists("comic.likeOrUnlikeComic")) {
return null;
}
return (id, isLiking) async {
try {
await JsEngine().runCode("""
ComicSource.sources.$_key.comic.likeOrUnlikeComic(${jsonEncode(id)}, ${jsonEncode(isLiking)})
""");
return const Res(true);
} catch (e, s) {
Log.error("Network", "$e\n$s");
return Res.error(e.toString());
}
};
}
} }

View File

@@ -86,6 +86,12 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
return comicSource!.loadComicInfo!(widget.id); return comicSource!.loadComicInfo!(widget.id);
} }
@override
onDataLoaded() {
isLiked = comic.isLiked ?? false;
isFavorite = comic.isFavorite ?? false;
}
Iterable<Widget> buildTitle() sync* { Iterable<Widget> buildTitle() sync* {
yield SliverAppbar( yield SliverAppbar(
title: AnimatedOpacity( title: AnimatedOpacity(
@@ -171,9 +177,9 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
_ActionButton( _ActionButton(
icon: const Icon(Icons.favorite_border), icon: const Icon(Icons.favorite_border),
activeIcon: const Icon(Icons.favorite), activeIcon: const Icon(Icons.favorite),
isActive: data!.isLiked, isActive: isLiked,
text: (data!.likesCount ?? text: (data!.likesCount ??
(comic.isLiked! ? 'Liked'.tl : 'Like'.tl)) (isLiked ? 'Liked'.tl : 'Like'.tl))
.toString(), .toString(),
isLoading: isLiking, isLoading: isLiking,
onPressed: likeOrUnlike, onPressed: likeOrUnlike,
@@ -182,18 +188,16 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
_ActionButton( _ActionButton(
icon: const Icon(Icons.bookmark_border), icon: const Icon(Icons.bookmark_border),
activeIcon: const Icon(Icons.bookmark), activeIcon: const Icon(Icons.bookmark),
isActive: (data!.isFavorite ?? false) || isAddToLocalFav, isActive: isFavorite || isAddToLocalFav,
text: 'Favorite'.tl, text: 'Favorite'.tl,
isLoading: isFavoriting, onPressed: openFavPanel,
onPressed: favoriteOrUnfavorite,
iconColor: context.useTextColor(Colors.purple), iconColor: context.useTextColor(Colors.purple),
), ),
if (comicSource.commentsLoader != null) if (comicSource.commentsLoader != null)
_ActionButton( _ActionButton(
icon: const Icon(Icons.comment), icon: const Icon(Icons.comment),
text: (comic.commentsCount ?? 'Comments'.tl).toString(), text: (comic.commentsCount ?? 'Comments'.tl).toString(),
isLoading: isFavoriting, onPressed: showComments,
onPressed: favoriteOrUnfavorite,
iconColor: context.useTextColor(Colors.green), iconColor: context.useTextColor(Colors.green),
), ),
_ActionButton( _ActionButton(
@@ -397,13 +401,27 @@ abstract mixin class _ComicPageActions {
bool isLiking = false; bool isLiking = false;
void likeOrUnlike() {} bool isLiked = false;
void likeOrUnlike() async {
if(isLiking) return;
isLiking = true;
update();
var res = await comicSource.likeOrUnlikeComic!(comic.id, isLiked ?? false);
if(res.error) {
App.rootContext.showMessage(message: res.errorMessage!);
} else {
isLiked = !isLiked;
}
isLiking = false;
update();
}
bool isAddToLocalFav = false; bool isAddToLocalFav = false;
bool isFavoriting = false; bool isFavorite = false;
void favoriteOrUnfavorite() {} void openFavPanel() {}
void share() {} void share() {}
@@ -421,6 +439,8 @@ abstract mixin class _ComicPageActions {
void onTagTap(String tag, String namespace) {} void onTagTap(String tag, String namespace) {}
void showMoreActions() {} void showMoreActions() {}
void showComments() {}
} }
class _ActionButton extends StatelessWidget { class _ActionButton extends StatelessWidget {
@@ -460,7 +480,11 @@ class _ActionButton extends StatelessWidget {
), ),
), ),
child: InkWell( child: InkWell(
onTap: onPressed, onTap: () {
if(!(isLoading ?? false)) {
onPressed();
}
},
borderRadius: BorderRadius.circular(18), borderRadius: BorderRadius.circular(18),
child: IconTheme.merge( child: IconTheme.merge(
data: IconThemeData(size: 20, color: iconColor), data: IconThemeData(size: 20, color: iconColor),