mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
improve html api;
fix thumbnails loading api; add favoriteId api
This commit is contained in:
@@ -242,9 +242,31 @@ function createUuid() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random integer between min and max
|
||||||
|
* @param min {number}
|
||||||
|
* @param max {number}
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
function randomInt(min, max) {
|
function randomInt(min, max) {
|
||||||
return sendMessage({
|
return sendMessage({
|
||||||
method: 'random',
|
method: 'random',
|
||||||
|
type: 'int',
|
||||||
|
min: min,
|
||||||
|
max: max
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random double between min and max
|
||||||
|
* @param min {number}
|
||||||
|
* @param max {number}
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function randomDouble(min, max) {
|
||||||
|
return sendMessage({
|
||||||
|
method: 'random',
|
||||||
|
type: 'double',
|
||||||
min: min,
|
min: min,
|
||||||
max: max
|
max: max
|
||||||
});
|
});
|
||||||
@@ -642,6 +664,45 @@ class HtmlElement {
|
|||||||
if(k == null) return null;
|
if(k == null) return null;
|
||||||
return new HtmlElement(k);
|
return new HtmlElement(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get class names of the element.
|
||||||
|
* @returns {string[]} An array of class names.
|
||||||
|
*/
|
||||||
|
get classNames() {
|
||||||
|
return sendMessage({
|
||||||
|
method: "html",
|
||||||
|
function: "getClassNames",
|
||||||
|
key: this.key,
|
||||||
|
doc: this.doc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get id of the element.
|
||||||
|
* @returns {string | null} The id of the element.
|
||||||
|
*/
|
||||||
|
get id() {
|
||||||
|
return sendMessage({
|
||||||
|
method: "html",
|
||||||
|
function: "getId",
|
||||||
|
key: this.key,
|
||||||
|
doc: this.doc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get local name of the element.
|
||||||
|
* @returns {string} The tag name of the element.
|
||||||
|
*/
|
||||||
|
get localName() {
|
||||||
|
return sendMessage({
|
||||||
|
method: "html",
|
||||||
|
function: "getLocalName",
|
||||||
|
key: this.key,
|
||||||
|
doc: this.doc,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HtmlNode {
|
class HtmlNode {
|
||||||
@@ -727,9 +788,10 @@ let console = {
|
|||||||
* @param description {string}
|
* @param description {string}
|
||||||
* @param maxPage {number?}
|
* @param maxPage {number?}
|
||||||
* @param language {string?}
|
* @param language {string?}
|
||||||
|
* @param favoriteId {string?} - Only set this field if the comic is from favorites page
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function Comic({id, title, subtitle, cover, tags, description, maxPage, language}) {
|
function Comic({id, title, subtitle, cover, tags, description, maxPage, language, favoriteId}) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.subtitle = subtitle;
|
this.subtitle = subtitle;
|
||||||
@@ -738,6 +800,7 @@ function Comic({id, title, subtitle, cover, tags, description, maxPage, language
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
this.maxPage = maxPage;
|
this.maxPage = maxPage;
|
||||||
this.language = language;
|
this.language = language;
|
||||||
|
this.favoriteId = favoriteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -749,7 +812,7 @@ function Comic({id, title, subtitle, cover, tags, description, maxPage, language
|
|||||||
* @param chapters {Map<string, string> | {} | null | undefined}} - key: chapter id, value: chapter title
|
* @param chapters {Map<string, string> | {} | null | undefined}} - key: chapter id, value: chapter title
|
||||||
* @param isFavorite {boolean | null | undefined}} - favorite status. If the comic source supports multiple folders, this field should be null
|
* @param isFavorite {boolean | null | undefined}} - favorite status. If the comic source supports multiple folders, this field should be null
|
||||||
* @param subId {string?} - a param which is passed to comments api
|
* @param subId {string?} - a param which is passed to comments api
|
||||||
* @param thumbnails {string[]? - for multiple page thumbnails, set this to null, and use `loadThumbnails` api to load thumbnails
|
* @param thumbnails {string[]?} - for multiple page thumbnails, set this to null, and use `loadThumbnails` api to load thumbnails
|
||||||
* @param recommend {Comic[]?} - related comics
|
* @param recommend {Comic[]?} - related comics
|
||||||
* @param commentCount {number?}
|
* @param commentCount {number?}
|
||||||
* @param likesCount {number?}
|
* @param likesCount {number?}
|
||||||
|
@@ -57,6 +57,7 @@ class _ToastOverlay extends StatelessWidget {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 16, fontWeight: FontWeight.w500),
|
fontSize: 16, fontWeight: FontWeight.w500),
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
if (trailing != null) trailing!.paddingLeft(8)
|
if (trailing != null) trailing!.paddingLeft(8)
|
||||||
],
|
],
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
part of 'comic_source.dart';
|
part of 'comic_source.dart';
|
||||||
|
|
||||||
typedef AddOrDelFavFunc = Future<Res<bool>> Function(String comicId, String folderId, bool isAdding);
|
typedef AddOrDelFavFunc = Future<Res<bool>> Function(String comicId, String folderId, bool isAdding, String? favId);
|
||||||
|
|
||||||
class FavoriteData{
|
class FavoriteData{
|
||||||
final String key;
|
final String key;
|
||||||
|
@@ -58,6 +58,8 @@ class Comic {
|
|||||||
|
|
||||||
final String? language;
|
final String? language;
|
||||||
|
|
||||||
|
final String? favoriteId;
|
||||||
|
|
||||||
const Comic(
|
const Comic(
|
||||||
this.title,
|
this.title,
|
||||||
this.cover,
|
this.cover,
|
||||||
@@ -68,7 +70,7 @@ class Comic {
|
|||||||
this.sourceKey,
|
this.sourceKey,
|
||||||
this.maxPage,
|
this.maxPage,
|
||||||
this.language,
|
this.language,
|
||||||
);
|
): favoriteId = null;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
@@ -81,6 +83,7 @@ class Comic {
|
|||||||
"sourceKey": sourceKey,
|
"sourceKey": sourceKey,
|
||||||
"maxPage": maxPage,
|
"maxPage": maxPage,
|
||||||
"language": language,
|
"language": language,
|
||||||
|
"favoriteId": favoriteId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +95,8 @@ class Comic {
|
|||||||
tags = List<String>.from(json["tags"] ?? []),
|
tags = List<String>.from(json["tags"] ?? []),
|
||||||
description = json["description"] ?? "",
|
description = json["description"] ?? "",
|
||||||
maxPage = json["maxPage"],
|
maxPage = json["maxPage"],
|
||||||
language = json["language"];
|
language = json["language"],
|
||||||
|
favoriteId = json["favoriteId"];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
|
@@ -202,7 +202,7 @@ class ComicSourceParser {
|
|||||||
JsEngine().runCode("ComicSource.sources.$_key.account.logout()");
|
JsEngine().runCode("ComicSource.sources.$_key.account.logout()");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_checkExists('account.loginWithWebview')) {
|
if (!_checkExists('account.loginWithWebview')) {
|
||||||
return AccountConfig(
|
return AccountConfig(
|
||||||
login,
|
login,
|
||||||
null,
|
null,
|
||||||
@@ -378,7 +378,7 @@ class ComicSourceParser {
|
|||||||
CategoryComicsData? _loadCategoryComicsData() {
|
CategoryComicsData? _loadCategoryComicsData() {
|
||||||
if (!_checkExists("categoryComics")) return null;
|
if (!_checkExists("categoryComics")) return null;
|
||||||
var options = <CategoryComicsOptions>[];
|
var options = <CategoryComicsOptions>[];
|
||||||
for (var element in _getValue("categoryComics.optionList")) {
|
for (var element in _getValue("categoryComics.optionList") ?? []) {
|
||||||
LinkedHashMap<String, String> map = LinkedHashMap<String, String>();
|
LinkedHashMap<String, String> map = LinkedHashMap<String, String>();
|
||||||
for (var option in element["options"]) {
|
for (var option in element["options"]) {
|
||||||
if (option.isEmpty || !option.contains("-")) {
|
if (option.isEmpty || !option.contains("-")) {
|
||||||
@@ -528,7 +528,12 @@ class ComicSourceParser {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Res<bool>> addOrDelFavFunc(comicId, folderId, isAdding) async {
|
Future<Res<bool>> addOrDelFavFunc(
|
||||||
|
String comicId,
|
||||||
|
String folderId,
|
||||||
|
bool isAdding,
|
||||||
|
String? favId,
|
||||||
|
) async {
|
||||||
func() async {
|
func() async {
|
||||||
try {
|
try {
|
||||||
await JsEngine().runCode("""
|
await JsEngine().runCode("""
|
||||||
@@ -703,13 +708,13 @@ class ComicSourceParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ComicThumbnailLoader? _parseThumbnailLoader() {
|
ComicThumbnailLoader? _parseThumbnailLoader() {
|
||||||
if (!_checkExists("comic.loadThumbnail")) {
|
if (!_checkExists("comic.loadThumbnails")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (id, next) async {
|
return (id, next) async {
|
||||||
try {
|
try {
|
||||||
var res = await JsEngine().runCode("""
|
var res = await JsEngine().runCode("""
|
||||||
ComicSource.sources.$_key.comic.loadThumbnail(${jsonEncode(id)}, ${jsonEncode(next)})
|
ComicSource.sources.$_key.comic.loadThumbnails(${jsonEncode(id)}, ${jsonEncode(next)})
|
||||||
""");
|
""");
|
||||||
return Res(List<String>.from(res['thumbnails']), subData: res['next']);
|
return Res(List<String>.from(res['thumbnails']), subData: res['next']);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
@@ -818,6 +823,7 @@ class ComicSourceParser {
|
|||||||
""");
|
""");
|
||||||
return res as String?;
|
return res as String?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LinkHandler(domains, linkToId);
|
return LinkHandler(domains, linkToId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -141,7 +141,11 @@ class JsEngine with _JSEngineApi {
|
|||||||
}
|
}
|
||||||
case "random":
|
case "random":
|
||||||
{
|
{
|
||||||
return _randomInt(message["min"], message["max"]);
|
return _random(
|
||||||
|
message["min"] ?? 0,
|
||||||
|
message["max"] ?? 1,
|
||||||
|
message["type"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
case "cookie":
|
case "cookie":
|
||||||
{
|
{
|
||||||
@@ -232,7 +236,7 @@ mixin class _JSEngineApi {
|
|||||||
Object? handleHtmlCallback(Map<String, dynamic> data) {
|
Object? handleHtmlCallback(Map<String, dynamic> data) {
|
||||||
switch (data["function"]) {
|
switch (data["function"]) {
|
||||||
case "parse":
|
case "parse":
|
||||||
if(_documents.length > 2) {
|
if (_documents.length > 2) {
|
||||||
_documents.remove(_documents.keys.first);
|
_documents.remove(_documents.keys.first);
|
||||||
}
|
}
|
||||||
_documents[data["key"]] = DocumentWrapper.parse(data["data"]);
|
_documents[data["key"]] = DocumentWrapper.parse(data["data"]);
|
||||||
@@ -276,6 +280,12 @@ mixin class _JSEngineApi {
|
|||||||
var docKey = data["key"];
|
var docKey = data["key"];
|
||||||
_documents.remove(docKey);
|
_documents.remove(docKey);
|
||||||
return null;
|
return null;
|
||||||
|
case "getClassNames":
|
||||||
|
return _documents[data["doc"]]!.getClassNames(data["key"]);
|
||||||
|
case "getId":
|
||||||
|
return _documents[data["doc"]]!.getId(data["key"]);
|
||||||
|
case "getLocalName":
|
||||||
|
return _documents[data["doc"]]!.getLocalName(data["key"]);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -455,7 +465,10 @@ mixin class _JSEngineApi {
|
|||||||
: output.sublist(0, outputOffset);
|
: output.sublist(0, outputOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _randomInt(int min, int max) {
|
num _random(num min, num max, String type) {
|
||||||
|
if (type == "double") {
|
||||||
|
return min + (max - min) * math.Random().nextDouble();
|
||||||
|
}
|
||||||
return (min + (max - min) * math.Random().nextDouble()).toInt();
|
return (min + (max - min) * math.Random().nextDouble()).toInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -568,4 +581,16 @@ class DocumentWrapper {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> getClassNames(int key) {
|
||||||
|
return (elements[key]).classes.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String? getId(int key) {
|
||||||
|
return (elements[key]).id;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? getLocalName(int key) {
|
||||||
|
return (elements[key]).localName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -124,6 +124,9 @@ class LocalComic with HistoryMixin implements Comic {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String? get language => null;
|
String? get language => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get favoriteId => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
class LocalManager with ChangeNotifier {
|
class LocalManager with ChangeNotifier {
|
||||||
|
@@ -840,43 +840,38 @@ class _ComicThumbnailsState extends State<_ComicThumbnails> {
|
|||||||
|
|
||||||
late List<String> thumbnails;
|
late List<String> thumbnails;
|
||||||
|
|
||||||
bool isInitialLoading = false;
|
bool isInitialLoading = true;
|
||||||
|
|
||||||
String? next;
|
String? next;
|
||||||
|
|
||||||
|
String? error;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
state = context.findAncestorStateOfType<_ComicPageState>()!;
|
state = context.findAncestorStateOfType<_ComicPageState>()!;
|
||||||
|
loadNext();
|
||||||
thumbnails = List.from(state.comic.thumbnails ?? []);
|
thumbnails = List.from(state.comic.thumbnails ?? []);
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLoading = false;
|
|
||||||
|
|
||||||
void loadNext() async {
|
void loadNext() async {
|
||||||
if (state.comicSource.loadComicThumbnail == null || isLoading) return;
|
if (state.comicSource.loadComicThumbnail == null) return;
|
||||||
if (!isInitialLoading && next == null) {
|
if (!isInitialLoading && next == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setState(() {
|
|
||||||
isLoading = true;
|
|
||||||
});
|
|
||||||
var res = await state.comicSource.loadComicThumbnail!(state.comic.id, next);
|
var res = await state.comicSource.loadComicThumbnail!(state.comic.id, next);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
thumbnails.addAll(res.data);
|
thumbnails.addAll(res.data);
|
||||||
next = res.subData;
|
next = res.subData;
|
||||||
isInitialLoading = false;
|
isInitialLoading = false;
|
||||||
|
} else {
|
||||||
|
error = res.errorMessage;
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {});
|
||||||
isLoading = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (thumbnails.isEmpty) {
|
|
||||||
Future.microtask(loadNext);
|
|
||||||
}
|
|
||||||
return SliverMainAxisGroup(
|
return SliverMainAxisGroup(
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
@@ -887,7 +882,7 @@ class _ComicThumbnailsState extends State<_ComicThumbnails> {
|
|||||||
SliverGrid(
|
SliverGrid(
|
||||||
delegate: SliverChildBuilderDelegate(childCount: thumbnails.length,
|
delegate: SliverChildBuilderDelegate(childCount: thumbnails.length,
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index == thumbnails.length - 1) {
|
if (index == thumbnails.length - 1 && error == null) {
|
||||||
loadNext();
|
loadNext();
|
||||||
}
|
}
|
||||||
return Padding(
|
return Padding(
|
||||||
@@ -940,7 +935,19 @@ class _ComicThumbnailsState extends State<_ComicThumbnails> {
|
|||||||
childAspectRatio: 0.65,
|
childAspectRatio: 0.65,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isLoading)
|
if(error != null)
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(error!),
|
||||||
|
Button.outlined(
|
||||||
|
onPressed: loadNext,
|
||||||
|
child: Text("Retry".tl),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (next != null || isInitialLoading)
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
child: ListLoadingIndicator(),
|
child: ListLoadingIndicator(),
|
||||||
),
|
),
|
||||||
@@ -1185,7 +1192,7 @@ class _NetworkFavoritesState extends State<_NetworkFavorites> {
|
|||||||
isLoading = true;
|
isLoading = true;
|
||||||
});
|
});
|
||||||
var res = await widget.comicSource.favoriteData!
|
var res = await widget.comicSource.favoriteData!
|
||||||
.addOrDelFavorite!(widget.cid, '', !isFavorite);
|
.addOrDelFavorite!(widget.cid, '', !isFavorite, null);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
widget.onFavorite(!isFavorite);
|
widget.onFavorite(!isFavorite);
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -1272,16 +1279,32 @@ class _NetworkFavoritesState extends State<_NetworkFavorites> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Center(
|
Center(
|
||||||
child: FilledButton(
|
child: Button.filled(
|
||||||
onPressed: () {
|
isLoading: isLoading,
|
||||||
|
onPressed: () async {
|
||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
widget.comicSource.favoriteData!.addOrDelFavorite!(
|
setState(() {
|
||||||
widget.cid, selected!, !addedFolders.contains(selected!));
|
isLoading = true;
|
||||||
context.pop();
|
});
|
||||||
|
var res = await widget.comicSource.favoriteData!.addOrDelFavorite!(
|
||||||
|
widget.cid,
|
||||||
|
selected!,
|
||||||
|
!addedFolders.contains(selected!),
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
if (res.success) {
|
||||||
|
context.showMessage(message: "Success".tl);
|
||||||
|
context.pop();
|
||||||
|
} else {
|
||||||
|
context.showMessage(message: res.errorMessage!);
|
||||||
|
setState(() {
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: addedFolders.contains(selected!)
|
child: selected != null && addedFolders.contains(selected!)
|
||||||
? Text("Remove".tl)
|
? Text("Remove".tl)
|
||||||
: Text("Add".tl),
|
: Text("Add".tl),
|
||||||
).paddingVertical(8),
|
).paddingVertical(8),
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
part of 'favorites_page.dart';
|
part of 'favorites_page.dart';
|
||||||
|
|
||||||
// TODO: Add a menu option to delete a comic from favorites
|
Future<bool> _deleteComic(
|
||||||
|
String cid,
|
||||||
Future<bool> _deleteComic(String cid, String? fid, String sourceKey) async {
|
String? fid,
|
||||||
|
String sourceKey,
|
||||||
|
String? favId,
|
||||||
|
) async {
|
||||||
var source = ComicSource.find(sourceKey);
|
var source = ComicSource.find(sourceKey);
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -31,6 +34,7 @@ Future<bool> _deleteComic(String cid, String? fid, String sourceKey) async {
|
|||||||
cid,
|
cid,
|
||||||
fid ?? '',
|
fid ?? '',
|
||||||
false,
|
false,
|
||||||
|
favId,
|
||||||
);
|
);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
context.showMessage(message: "Deleted".tl);
|
context.showMessage(message: "Deleted".tl);
|
||||||
@@ -115,7 +119,12 @@ class _NormalFavoritePage extends StatelessWidget {
|
|||||||
icon: Icons.delete_outline,
|
icon: Icons.delete_outline,
|
||||||
text: "Remove".tl,
|
text: "Remove".tl,
|
||||||
onClick: () async {
|
onClick: () async {
|
||||||
var res = await _deleteComic(comic.id, null, comic.sourceKey);
|
var res = await _deleteComic(
|
||||||
|
comic.id,
|
||||||
|
null,
|
||||||
|
comic.sourceKey,
|
||||||
|
comic.favoriteId,
|
||||||
|
);
|
||||||
if (res) {
|
if (res) {
|
||||||
comicListKey.currentState!.remove(comic);
|
comicListKey.currentState!.remove(comic);
|
||||||
}
|
}
|
||||||
@@ -291,14 +300,16 @@ class _MultiFolderFavoritesPageState extends State<_MultiFolderFavoritesPage> {
|
|||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return _CreateFolderDialog(
|
return _CreateFolderDialog(
|
||||||
widget.data,
|
widget.data,
|
||||||
() => setState(() {
|
() => setState(() {
|
||||||
_loading = true;
|
_loading = true;
|
||||||
}));
|
}),
|
||||||
});
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -382,7 +393,7 @@ class _FolderTile extends StatelessWidget {
|
|||||||
return StatefulBuilder(builder: (context, setState) {
|
return StatefulBuilder(builder: (context, setState) {
|
||||||
return ContentDialog(
|
return ContentDialog(
|
||||||
title: "Delete".tl,
|
title: "Delete".tl,
|
||||||
content: Text("Are you sure you want to delete this folder?".tl),
|
content: Text("Are you sure you want to delete this folder?".tl).paddingHorizontal(16),
|
||||||
actions: [
|
actions: [
|
||||||
Button.filled(
|
Button.filled(
|
||||||
isLoading: loading,
|
isLoading: loading,
|
||||||
@@ -448,36 +459,37 @@ class _CreateFolderDialogState extends State<_CreateFolderDialog> {
|
|||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
if (loading)
|
if (loading)
|
||||||
const SizedBox(
|
Center(
|
||||||
child: Center(
|
child: const CircularProgressIndicator(
|
||||||
child: CircularProgressIndicator(),
|
strokeWidth: 2,
|
||||||
),
|
).fixWidth(24).fixHeight(24),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 35,
|
height: 35,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
loading = true;
|
||||||
|
});
|
||||||
|
widget.data.addFolder!(controller.text).then((b) {
|
||||||
|
if (b.error) {
|
||||||
|
context.showMessage(message: b.errorMessage!);
|
||||||
setState(() {
|
setState(() {
|
||||||
loading = true;
|
loading = false;
|
||||||
});
|
});
|
||||||
widget.data.addFolder!(controller.text).then((b) {
|
} else {
|
||||||
if (b.error) {
|
context.pop();
|
||||||
context.showMessage(message: b.errorMessage!);
|
context.showMessage(message: "Created successfully".tl);
|
||||||
setState(() {
|
widget.updateState();
|
||||||
loading = false;
|
}
|
||||||
});
|
});
|
||||||
} else {
|
},
|
||||||
context.pop();
|
child: Text("Submit".tl),
|
||||||
context.showMessage(
|
),
|
||||||
message: "Created successfully".tl);
|
),
|
||||||
widget.updateState();
|
)
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Text("Submit".tl)),
|
|
||||||
))
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -501,6 +513,9 @@ class _FavoriteFolder extends StatelessWidget {
|
|||||||
leadingSliver: SliverAppbar(
|
leadingSliver: SliverAppbar(
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
),
|
),
|
||||||
|
errorLeading: Appbar(
|
||||||
|
title: Text(title),
|
||||||
|
),
|
||||||
loadPage: (i) => data.loadComic(i, folderID),
|
loadPage: (i) => data.loadComic(i, folderID),
|
||||||
menuBuilder: (comic) {
|
menuBuilder: (comic) {
|
||||||
return [
|
return [
|
||||||
@@ -508,7 +523,12 @@ class _FavoriteFolder extends StatelessWidget {
|
|||||||
icon: Icons.delete_outline,
|
icon: Icons.delete_outline,
|
||||||
text: "Remove".tl,
|
text: "Remove".tl,
|
||||||
onClick: () async {
|
onClick: () async {
|
||||||
var res = await _deleteComic(comic.id, null, comic.sourceKey);
|
var res = await _deleteComic(
|
||||||
|
comic.id,
|
||||||
|
null,
|
||||||
|
comic.sourceKey,
|
||||||
|
comic.favoriteId,
|
||||||
|
);
|
||||||
if (res) {
|
if (res) {
|
||||||
comicListKey.currentState!.remove(comic);
|
comicListKey.currentState!.remove(comic);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user