diff --git a/lib/components/loading.dart b/lib/components/loading.dart index 361d746..fd9bad8 100644 --- a/lib/components/loading.dart +++ b/lib/components/loading.dart @@ -95,6 +95,8 @@ abstract class LoadingState Future> loadData(); + void onDataLoaded() {} + Widget buildContent(BuildContext context, S data); Widget? buildFrame(BuildContext context, Widget child) => null; @@ -118,6 +120,7 @@ abstract class LoadingState isLoading = false; data = value.data; }); + onDataLoaded(); } else { setState(() { isLoading = false; diff --git a/lib/foundation/comic_source/comic_source.dart b/lib/foundation/comic_source/comic_source.dart index 353e485..ba495c9 100644 --- a/lib/foundation/comic_source/comic_source.dart +++ b/lib/foundation/comic_source/comic_source.dart @@ -3,7 +3,6 @@ library comic_source; import 'dart:async'; import 'dart:collection'; import 'dart:convert'; -import 'dart:io'; import 'dart:math' as math; import 'package:flutter/widgets.dart'; @@ -45,6 +44,8 @@ typedef GetThumbnailLoadingConfigFunc = Map Function( typedef ComicThumbnailLoader = Future>> Function(String comicId, String? next); +typedef LikeOrUnlikeComicFunc = Future> Function(String comicId, bool isLiking); + class ComicSource { static final List _sources = []; @@ -171,6 +172,8 @@ class ComicSource { final RegExp? idMatcher; + final LikeOrUnlikeComicFunc? likeOrUnlikeComic; + Future loadData() async { var file = File("${App.dataPath}/comic_source/$key.data"); if (await file.exists()) { @@ -229,7 +232,8 @@ class ComicSource { this.url, this.version, this.commentsLoader, - this.sendCommentFunc) + this.sendCommentFunc, + this.likeOrUnlikeComic) : idMatcher = null; ComicSource.unknown(this.key) @@ -252,7 +256,8 @@ class ComicSource { version = "", commentsLoader = null, sendCommentFunc = null, - idMatcher = null; + idMatcher = null, + likeOrUnlikeComic = null; } class AccountConfig { diff --git a/lib/foundation/comic_source/parser.dart b/lib/foundation/comic_source/parser.dart index 51cc86c..18a1af5 100644 --- a/lib/foundation/comic_source/parser.dart +++ b/lib/foundation/comic_source/parser.dart @@ -136,6 +136,7 @@ class ComicSourceParser { final favoriteData = _loadFavoriteData(); final commentsLoader = _parseCommentsLoader(); final sendCommentFunc = _parseSendCommentFunc(); + final likeFunc = _parseLikeFunc(); var source = ComicSource( _name!, @@ -158,6 +159,7 @@ class ComicSourceParser { version ?? "1.0.0", commentsLoader, sendCommentFunc, + likeFunc, ); 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()); + } + }; + } } diff --git a/lib/pages/comic_page.dart b/lib/pages/comic_page.dart index f7fc44e..3627acb 100644 --- a/lib/pages/comic_page.dart +++ b/lib/pages/comic_page.dart @@ -86,6 +86,12 @@ class _ComicPageState extends LoadingState return comicSource!.loadComicInfo!(widget.id); } + @override + onDataLoaded() { + isLiked = comic.isLiked ?? false; + isFavorite = comic.isFavorite ?? false; + } + Iterable buildTitle() sync* { yield SliverAppbar( title: AnimatedOpacity( @@ -171,9 +177,9 @@ class _ComicPageState extends LoadingState _ActionButton( icon: const Icon(Icons.favorite_border), activeIcon: const Icon(Icons.favorite), - isActive: data!.isLiked, + isActive: isLiked, text: (data!.likesCount ?? - (comic.isLiked! ? 'Liked'.tl : 'Like'.tl)) + (isLiked ? 'Liked'.tl : 'Like'.tl)) .toString(), isLoading: isLiking, onPressed: likeOrUnlike, @@ -182,18 +188,16 @@ class _ComicPageState extends LoadingState _ActionButton( icon: const Icon(Icons.bookmark_border), activeIcon: const Icon(Icons.bookmark), - isActive: (data!.isFavorite ?? false) || isAddToLocalFav, + isActive: isFavorite || isAddToLocalFav, text: 'Favorite'.tl, - isLoading: isFavoriting, - onPressed: favoriteOrUnfavorite, + onPressed: openFavPanel, iconColor: context.useTextColor(Colors.purple), ), if (comicSource.commentsLoader != null) _ActionButton( icon: const Icon(Icons.comment), text: (comic.commentsCount ?? 'Comments'.tl).toString(), - isLoading: isFavoriting, - onPressed: favoriteOrUnfavorite, + onPressed: showComments, iconColor: context.useTextColor(Colors.green), ), _ActionButton( @@ -397,13 +401,27 @@ abstract mixin class _ComicPageActions { 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 isFavoriting = false; + bool isFavorite = false; - void favoriteOrUnfavorite() {} + void openFavPanel() {} void share() {} @@ -421,6 +439,8 @@ abstract mixin class _ComicPageActions { void onTagTap(String tag, String namespace) {} void showMoreActions() {} + + void showComments() {} } class _ActionButton extends StatelessWidget { @@ -460,7 +480,11 @@ class _ActionButton extends StatelessWidget { ), ), child: InkWell( - onTap: onPressed, + onTap: () { + if(!(isLoading ?? false)) { + onPressed(); + } + }, borderRadius: BorderRadius.circular(18), child: IconTheme.merge( data: IconThemeData(size: 20, color: iconColor),