mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
quick favorite
This commit is contained in:
@@ -185,7 +185,10 @@
|
|||||||
"Saved": "已保存",
|
"Saved": "已保存",
|
||||||
"Sync Data": "同步数据",
|
"Sync Data": "同步数据",
|
||||||
"Syncing Data": "正在同步数据",
|
"Syncing Data": "正在同步数据",
|
||||||
"Data Sync": "数据同步"
|
"Data Sync": "数据同步",
|
||||||
|
"Quick Favorite": "快速收藏",
|
||||||
|
"Long press on the favorite button to quickly add to this folder": "长按收藏按钮快速添加到这个文件夹",
|
||||||
|
"Added": "已添加"
|
||||||
},
|
},
|
||||||
"zh_TW": {
|
"zh_TW": {
|
||||||
"Home": "首頁",
|
"Home": "首頁",
|
||||||
@@ -373,6 +376,9 @@
|
|||||||
"Saved": "已保存",
|
"Saved": "已保存",
|
||||||
"Sync Data": "同步數據",
|
"Sync Data": "同步數據",
|
||||||
"Syncing Data": "正在同步數據",
|
"Syncing Data": "正在同步數據",
|
||||||
"Data Sync": "數據同步"
|
"Data Sync": "數據同步",
|
||||||
|
"Quick Favorite": "快速收藏",
|
||||||
|
"Long press on the favorite button to quickly add to this folder": "長按收藏按鈕快速添加到這個文件夾",
|
||||||
|
"Added": "已添加"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -116,6 +116,7 @@ class _Settings with ChangeNotifier {
|
|||||||
'limitImageWidth': true,
|
'limitImageWidth': true,
|
||||||
'webdav': [], // empty means not configured
|
'webdav': [], // empty means not configured
|
||||||
'dataVersion': 0,
|
'dataVersion': 0,
|
||||||
|
'quickFavorite': null,
|
||||||
};
|
};
|
||||||
|
|
||||||
operator [](String key) {
|
operator [](String key) {
|
||||||
|
@@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.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/appdata.dart';
|
||||||
import 'package:venera/foundation/comic_source/comic_source.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/consts.dart';
|
import 'package:venera/foundation/consts.dart';
|
||||||
@@ -282,6 +283,7 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
|
|||||||
isActive: isFavorite || isAddToLocalFav,
|
isActive: isFavorite || isAddToLocalFav,
|
||||||
text: 'Favorite'.tl,
|
text: 'Favorite'.tl,
|
||||||
onPressed: openFavPanel,
|
onPressed: openFavPanel,
|
||||||
|
onLongPressed: quickFavorite,
|
||||||
iconColor: context.useTextColor(Colors.purple),
|
iconColor: context.useTextColor(Colors.purple),
|
||||||
),
|
),
|
||||||
if (comicSource.commentsLoader != null)
|
if (comicSource.commentsLoader != null)
|
||||||
@@ -538,12 +540,22 @@ abstract mixin class _ComicPageActions {
|
|||||||
|
|
||||||
bool isFavorite = false;
|
bool isFavorite = false;
|
||||||
|
|
||||||
void openFavPanel() {
|
FavoriteItem _toFavoriteItem() {
|
||||||
var tags = <String>[];
|
var tags = <String>[];
|
||||||
for (var e in comic.tags.entries) {
|
for (var e in comic.tags.entries) {
|
||||||
tags.addAll(e.value.map((tag) => '${e.key}:$tag'));
|
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(
|
showSideBar(
|
||||||
App.rootContext,
|
App.rootContext,
|
||||||
_FavoritePanel(
|
_FavoritePanel(
|
||||||
@@ -555,18 +567,25 @@ abstract mixin class _ComicPageActions {
|
|||||||
isAddToLocalFav = local ?? isAddToLocalFav;
|
isAddToLocalFav = local ?? isAddToLocalFav;
|
||||||
update();
|
update();
|
||||||
},
|
},
|
||||||
favoriteItem: FavoriteItem(
|
favoriteItem: _toFavoriteItem(),
|
||||||
id: comic.id,
|
|
||||||
name: comic.title,
|
|
||||||
coverPath: comic.cover,
|
|
||||||
author: comic.subTitle ?? comic.uploader ?? '',
|
|
||||||
type: comic.comicType,
|
|
||||||
tags: tags,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void quickFavorite() {
|
||||||
|
var folder = appdata.settings['quickFavorite'];
|
||||||
|
if(folder is! String) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LocalFavoritesManager().addComic(
|
||||||
|
folder,
|
||||||
|
_toFavoriteItem(),
|
||||||
|
);
|
||||||
|
isAddToLocalFav = true;
|
||||||
|
update();
|
||||||
|
App.rootContext.showMessage(message: "Added".tl);
|
||||||
|
}
|
||||||
|
|
||||||
void share() {
|
void share() {
|
||||||
var text = comic.title;
|
var text = comic.title;
|
||||||
if (comic.url != null) {
|
if (comic.url != null) {
|
||||||
@@ -800,6 +819,7 @@ class _ActionButton extends StatelessWidget {
|
|||||||
required this.icon,
|
required this.icon,
|
||||||
required this.text,
|
required this.text,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
|
this.onLongPressed,
|
||||||
this.activeIcon,
|
this.activeIcon,
|
||||||
this.isActive,
|
this.isActive,
|
||||||
this.isLoading,
|
this.isLoading,
|
||||||
@@ -820,6 +840,8 @@ class _ActionButton extends StatelessWidget {
|
|||||||
|
|
||||||
final Color? iconColor;
|
final Color? iconColor;
|
||||||
|
|
||||||
|
final void Function()? onLongPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@@ -837,6 +859,7 @@ class _ActionButton extends StatelessWidget {
|
|||||||
onPressed();
|
onPressed();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onLongPress: onLongPressed,
|
||||||
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),
|
||||||
|
@@ -24,12 +24,20 @@ class _LocalFavoritesSettingsState extends State<LocalFavoritesSettings> {
|
|||||||
SelectSetting(
|
SelectSetting(
|
||||||
title: "Move favorite after reading".tl,
|
title: "Move favorite after reading".tl,
|
||||||
settingKey: "moveFavoriteAfterRead",
|
settingKey: "moveFavoriteAfterRead",
|
||||||
optionTranslation: {
|
optionTranslation: const {
|
||||||
"none": "None",
|
"none": "None",
|
||||||
"end": "End",
|
"end": "End",
|
||||||
"start": "Start",
|
"start": "Start",
|
||||||
},
|
},
|
||||||
).toSliver(),
|
).toSliver(),
|
||||||
|
SelectSetting(
|
||||||
|
title: "Quick Favorite".tl,
|
||||||
|
settingKey: "quickFavorite",
|
||||||
|
help: "Long press on the favorite button to quickly add to this folder".tl,
|
||||||
|
optionTranslation: {
|
||||||
|
for (var e in LocalFavoritesManager().folderNames) e: e
|
||||||
|
},
|
||||||
|
).toSliver(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -49,6 +49,7 @@ class SelectSetting extends StatelessWidget {
|
|||||||
required this.settingKey,
|
required this.settingKey,
|
||||||
required this.optionTranslation,
|
required this.optionTranslation,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
|
this.help,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
@@ -59,6 +60,8 @@ class SelectSetting extends StatelessWidget {
|
|||||||
|
|
||||||
final VoidCallback? onChanged;
|
final VoidCallback? onChanged;
|
||||||
|
|
||||||
|
final String? help;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
@@ -71,6 +74,7 @@ class SelectSetting extends StatelessWidget {
|
|||||||
settingKey: settingKey,
|
settingKey: settingKey,
|
||||||
optionTranslation: optionTranslation,
|
optionTranslation: optionTranslation,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
|
help: help,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return _EndSelectorSelectSetting(
|
return _EndSelectorSelectSetting(
|
||||||
@@ -78,6 +82,7 @@ class SelectSetting extends StatelessWidget {
|
|||||||
settingKey: settingKey,
|
settingKey: settingKey,
|
||||||
optionTranslation: optionTranslation,
|
optionTranslation: optionTranslation,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
|
help: help,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -92,6 +97,7 @@ class _DoubleLineSelectSettings extends StatefulWidget {
|
|||||||
required this.settingKey,
|
required this.settingKey,
|
||||||
required this.optionTranslation,
|
required this.optionTranslation,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
|
this.help,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
@@ -102,6 +108,8 @@ class _DoubleLineSelectSettings extends StatefulWidget {
|
|||||||
|
|
||||||
final VoidCallback? onChanged;
|
final VoidCallback? onChanged;
|
||||||
|
|
||||||
|
final String? help;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_DoubleLineSelectSettings> createState() =>
|
State<_DoubleLineSelectSettings> createState() =>
|
||||||
_DoubleLineSelectSettingsState();
|
_DoubleLineSelectSettingsState();
|
||||||
@@ -111,9 +119,37 @@ class _DoubleLineSelectSettingsState extends State<_DoubleLineSelectSettings> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(widget.title),
|
title: Row(
|
||||||
subtitle:
|
children: [
|
||||||
Text(widget.optionTranslation[appdata.settings[widget.settingKey]]!),
|
Text(widget.title),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
if (widget.help != null)
|
||||||
|
Button.icon(
|
||||||
|
size: 18,
|
||||||
|
icon: const Icon(Icons.help_outline),
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return ContentDialog(
|
||||||
|
title: "Help".tl,
|
||||||
|
content: Text(widget.help!).paddingHorizontal(16).fixWidth(double.infinity),
|
||||||
|
actions: [
|
||||||
|
Button.filled(
|
||||||
|
onPressed: context.pop,
|
||||||
|
child: Text("OK".tl),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
widget.optionTranslation[appdata.settings[widget.settingKey]] ??
|
||||||
|
"None"),
|
||||||
trailing: const Icon(Icons.arrow_drop_down),
|
trailing: const Icon(Icons.arrow_drop_down),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
var renderBox = context.findRenderObject() as RenderBox;
|
var renderBox = context.findRenderObject() as RenderBox;
|
||||||
@@ -156,6 +192,7 @@ class _EndSelectorSelectSetting extends StatefulWidget {
|
|||||||
required this.settingKey,
|
required this.settingKey,
|
||||||
required this.optionTranslation,
|
required this.optionTranslation,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
|
this.help,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
@@ -166,6 +203,8 @@ class _EndSelectorSelectSetting extends StatefulWidget {
|
|||||||
|
|
||||||
final VoidCallback? onChanged;
|
final VoidCallback? onChanged;
|
||||||
|
|
||||||
|
final String? help;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_EndSelectorSelectSetting> createState() =>
|
State<_EndSelectorSelectSetting> createState() =>
|
||||||
_EndSelectorSelectSettingState();
|
_EndSelectorSelectSettingState();
|
||||||
@@ -176,10 +215,38 @@ class _EndSelectorSelectSettingState extends State<_EndSelectorSelectSetting> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var options = widget.optionTranslation;
|
var options = widget.optionTranslation;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(widget.title),
|
title: Row(
|
||||||
|
children: [
|
||||||
|
Text(widget.title),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
if (widget.help != null)
|
||||||
|
Button.icon(
|
||||||
|
size: 18,
|
||||||
|
icon: const Icon(Icons.help_outline),
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return ContentDialog(
|
||||||
|
title: "Help".tl,
|
||||||
|
content: Text(widget.help!).paddingHorizontal(16).fixWidth(double.infinity),
|
||||||
|
actions: [
|
||||||
|
Button.filled(
|
||||||
|
onPressed: context.pop,
|
||||||
|
child: Text("OK".tl),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
trailing: Select(
|
trailing: Select(
|
||||||
current: options[appdata.settings[widget.settingKey]]!,
|
current: options[appdata.settings[widget.settingKey]],
|
||||||
values: options.values.toList(),
|
values: options.values.toList(),
|
||||||
|
minWidth: 64,
|
||||||
onTap: (index) {
|
onTap: (index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
appdata.settings[widget.settingKey] = options.keys.elementAt(index);
|
appdata.settings[widget.settingKey] = options.keys.elementAt(index);
|
||||||
|
@@ -11,6 +11,7 @@ import 'package:venera/foundation/appdata.dart';
|
|||||||
import 'package:venera/foundation/cache_manager.dart';
|
import 'package:venera/foundation/cache_manager.dart';
|
||||||
import 'package:venera/foundation/comic_source/comic_source.dart';
|
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||||
import 'package:venera/foundation/consts.dart';
|
import 'package:venera/foundation/consts.dart';
|
||||||
|
import 'package:venera/foundation/favorites.dart';
|
||||||
import 'package:venera/foundation/local.dart';
|
import 'package:venera/foundation/local.dart';
|
||||||
import 'package:venera/foundation/log.dart';
|
import 'package:venera/foundation/log.dart';
|
||||||
import 'package:venera/network/app_dio.dart';
|
import 'package:venera/network/app_dio.dart';
|
||||||
|
Reference in New Issue
Block a user