mirror of
https://github.com/wgh136/pixes.git
synced 2025-09-27 04:57:23 +00:00
settings
This commit is contained in:
@@ -20,11 +20,28 @@ class _Appdata {
|
|||||||
"useTranslatedNameForDownload": false,
|
"useTranslatedNameForDownload": false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool lock = false;
|
||||||
|
|
||||||
void writeData() async {
|
void writeData() async {
|
||||||
|
while (lock) {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 20));
|
||||||
|
}
|
||||||
|
lock = true;
|
||||||
await File("${App.dataPath}/account.json")
|
await File("${App.dataPath}/account.json")
|
||||||
.writeAsString(jsonEncode(account));
|
.writeAsString(jsonEncode(account));
|
||||||
await File("${App.dataPath}/settings.json")
|
await File("${App.dataPath}/settings.json")
|
||||||
.writeAsString(jsonEncode(settings));
|
.writeAsString(jsonEncode(settings));
|
||||||
|
lock = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSettings() async {
|
||||||
|
while (lock) {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 20));
|
||||||
|
}
|
||||||
|
lock = true;
|
||||||
|
await File("${App.dataPath}/settings.json")
|
||||||
|
.writeAsString(jsonEncode(settings));
|
||||||
|
lock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> readData() async {
|
Future<void> readData() async {
|
||||||
@@ -35,17 +52,17 @@ class _Appdata {
|
|||||||
final settingsFile = File("${App.dataPath}/settings.json");
|
final settingsFile = File("${App.dataPath}/settings.json");
|
||||||
if (settingsFile.existsSync()) {
|
if (settingsFile.existsSync()) {
|
||||||
var json = jsonDecode(await settingsFile.readAsString());
|
var json = jsonDecode(await settingsFile.readAsString());
|
||||||
for(var key in json.keys) {
|
for (var key in json.keys) {
|
||||||
settings[key] = json[key];
|
settings[key] = json[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(settings["downloadPath"] == null) {
|
if (settings["downloadPath"] == null) {
|
||||||
settings["downloadPath"] = await _defaultDownloadPath;
|
settings["downloadPath"] = await _defaultDownloadPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> get _defaultDownloadPath async{
|
Future<String> get _defaultDownloadPath async {
|
||||||
if(App.isAndroid) {
|
if (App.isAndroid) {
|
||||||
String? downloadPath = "/storage/emulated/0/download";
|
String? downloadPath = "/storage/emulated/0/download";
|
||||||
if (!Directory(downloadPath).havePermission()) {
|
if (!Directory(downloadPath).havePermission()) {
|
||||||
downloadPath = null;
|
downloadPath = null;
|
||||||
@@ -53,14 +70,15 @@ class _Appdata {
|
|||||||
var res = downloadPath;
|
var res = downloadPath;
|
||||||
res ??= (await getExternalStorageDirectory())!.path;
|
res ??= (await getExternalStorageDirectory())!.path;
|
||||||
return "$res/pixes";
|
return "$res/pixes";
|
||||||
} else if (App.isWindows){
|
} else if (App.isWindows) {
|
||||||
var res = await const MethodChannel("pixes/picture_folder").invokeMethod("");
|
var res =
|
||||||
if(res != "error") {
|
await const MethodChannel("pixes/picture_folder").invokeMethod("");
|
||||||
|
if (res != "error") {
|
||||||
return res + "/pixes";
|
return res + "/pixes";
|
||||||
}
|
}
|
||||||
} else if (App.isMacOS || App.isLinux) {
|
} else if (App.isMacOS || App.isLinux) {
|
||||||
var downloadPath = (await getDownloadsDirectory())?.path;
|
var downloadPath = (await getDownloadsDirectory())?.path;
|
||||||
if(downloadPath != null && Directory(downloadPath).havePermission()) {
|
if (downloadPath != null && Directory(downloadPath).havePermission()) {
|
||||||
return "$downloadPath/pixes";
|
return "$downloadPath/pixes";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,8 @@ export "state_controller.dart";
|
|||||||
export "navigation.dart";
|
export "navigation.dart";
|
||||||
|
|
||||||
class _App {
|
class _App {
|
||||||
|
final version = "1.0.0";
|
||||||
|
|
||||||
bool get isAndroid => Platform.isAndroid;
|
bool get isAndroid => Platform.isAndroid;
|
||||||
bool get isIOS => Platform.isIOS;
|
bool get isIOS => Platform.isIOS;
|
||||||
bool get isWindows => Platform.isWindows;
|
bool get isWindows => Platform.isWindows;
|
||||||
|
@@ -114,11 +114,15 @@ class DownloadingTask {
|
|||||||
static String _generateFilePath(Illust illust, int index, String ext) {
|
static String _generateFilePath(Illust illust, int index, String ext) {
|
||||||
final String downloadPath = appdata.settings["downloadPath"];
|
final String downloadPath = appdata.settings["downloadPath"];
|
||||||
String subPathPatten = appdata.settings["downloadSubPath"];
|
String subPathPatten = appdata.settings["downloadSubPath"];
|
||||||
final tags = appdata.settings["useTranslatedNameForDownload"] == false
|
|
||||||
? illust.tags.map((e) => e.name).toList()
|
|
||||||
: illust.tags.map((e) => e.translatedName ?? e.name).toList();
|
|
||||||
final tagsWeight = (appdata.settings["tagsWeight"] as String).split(' ');
|
final tagsWeight = (appdata.settings["tagsWeight"] as String).split(' ');
|
||||||
tags.sort((a, b) => tagsWeight.indexOf(a) - tagsWeight.indexOf(b));
|
final originalTags = List<Tag>.from(illust.tags);
|
||||||
|
originalTags.sort((a, b){
|
||||||
|
return tagsWeight.indexOf(a.name) - tagsWeight.indexOf(b.name);
|
||||||
|
});
|
||||||
|
final tags = appdata.settings["useTranslatedNameForDownload"] == false
|
||||||
|
? originalTags.map((e) => e.name).toList()
|
||||||
|
: originalTags.map((e) => e.translatedName ?? e.name).toList();
|
||||||
|
|
||||||
subPathPatten = subPathPatten.replaceAll(r"${id}", illust.id.toString());
|
subPathPatten = subPathPatten.replaceAll(r"${id}", illust.id.toString());
|
||||||
subPathPatten = subPathPatten.replaceAll(r"${title}", illust.title);
|
subPathPatten = subPathPatten.replaceAll(r"${title}", illust.title);
|
||||||
subPathPatten = subPathPatten.replaceAll(r"${author}", illust.author.name);
|
subPathPatten = subPathPatten.replaceAll(r"${author}", illust.author.name);
|
||||||
|
@@ -106,7 +106,14 @@ class Network {
|
|||||||
},
|
},
|
||||||
options: Options(
|
options: Options(
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
validateStatus: (i) => true,
|
||||||
headers: headers));
|
headers: headers));
|
||||||
|
if(res.statusCode != 200) {
|
||||||
|
var data = res.data ?? "";
|
||||||
|
if(data.contains("Invalid refresh token")) {
|
||||||
|
throw "Failed to refresh token. Plaese logout and re-login";
|
||||||
|
}
|
||||||
|
}
|
||||||
var account = Account.fromJson(json.decode(res.data!));
|
var account = Account.fromJson(json.decode(res.data!));
|
||||||
appdata.account = account;
|
appdata.account = account;
|
||||||
appdata.writeData();
|
appdata.writeData();
|
||||||
|
@@ -1,9 +1,14 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
import 'package:pixes/appdata.dart';
|
import 'package:pixes/appdata.dart';
|
||||||
|
import 'package:pixes/components/md.dart';
|
||||||
|
import 'package:pixes/components/message.dart';
|
||||||
import 'package:pixes/components/page_route.dart';
|
import 'package:pixes/components/page_route.dart';
|
||||||
import 'package:pixes/components/title_bar.dart';
|
import 'package:pixes/components/title_bar.dart';
|
||||||
import 'package:pixes/foundation/app.dart';
|
import 'package:pixes/foundation/app.dart';
|
||||||
import 'package:pixes/pages/main_page.dart';
|
import 'package:pixes/pages/main_page.dart';
|
||||||
|
import 'package:pixes/utils/io.dart';
|
||||||
import 'package:pixes/utils/translation.dart';
|
import 'package:pixes/utils/translation.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
@@ -24,7 +29,12 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
SliverTitleBar(title: "Settings".tl),
|
SliverTitleBar(title: "Settings".tl),
|
||||||
buildHeader("Account".tl),
|
buildHeader("Account".tl),
|
||||||
buildAccount(),
|
buildAccount(),
|
||||||
SliverPadding(padding: EdgeInsets.only(bottom: context.padding.bottom)),
|
buildHeader("Download".tl),
|
||||||
|
buildDownload(),
|
||||||
|
buildHeader("About".tl),
|
||||||
|
buildAbout(),
|
||||||
|
SliverPadding(
|
||||||
|
padding: EdgeInsets.only(bottom: context.padding.bottom)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -34,8 +44,10 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
return SliverToBoxAdapter(
|
return SliverToBoxAdapter(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||||
child: Text(text, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
|
child: Text(text,
|
||||||
),);
|
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildItem({required String title, String? subtitle, Widget? action}) {
|
Widget buildItem({required String title, String? subtitle, Widget? action}) {
|
||||||
@@ -49,8 +61,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildAccount(){
|
Widget buildAccount() {
|
||||||
return SliverToBoxAdapter(
|
return SliverToBoxAdapter(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -71,8 +83,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
App.rootNavigatorKey.currentState!.pushAndRemoveUntil(
|
App.rootNavigatorKey.currentState!.pushAndRemoveUntil(
|
||||||
AppPageRoute(
|
AppPageRoute(
|
||||||
builder: (context) => const MainPage()),
|
builder: (context) => const MainPage()),
|
||||||
(route) => false
|
(route) => false);
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
@@ -86,14 +97,209 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
child: Text("Continue".tl).fixWidth(64),
|
child: Text("Continue".tl).fixWidth(64),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
buildItem(title: "Account Settings".tl, action: Button(
|
buildItem(
|
||||||
child: Text("Edit".tl).fixWidth(64),
|
title: "Account Settings".tl,
|
||||||
onPressed: (){
|
action: Button(
|
||||||
launchUrlString("https://www.pixiv.net/setting_user.php");
|
child: Text("Edit".tl).fixWidth(64),
|
||||||
},
|
onPressed: () {
|
||||||
)),
|
launchUrlString("https://www.pixiv.net/setting_user.php");
|
||||||
|
},
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Widget buildDownload() {
|
||||||
|
return SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
buildItem(
|
||||||
|
title: "Download Path",
|
||||||
|
subtitle: appdata.settings["downloadPath"],
|
||||||
|
action: Button(
|
||||||
|
child: Text("Manage".tl).fixWidth(64),
|
||||||
|
onPressed: () {
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
showToast(context, message: "Unsupport platform".tl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.to(() => const _SetDownloadPathPage());
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
buildItem(
|
||||||
|
title: "Subpath",
|
||||||
|
subtitle: appdata.settings["downloadSubPath"],
|
||||||
|
action: Button(
|
||||||
|
child: Text("Manage".tl).fixWidth(64),
|
||||||
|
onPressed: () {
|
||||||
|
context.to(() => const _SetDownloadSubPathPage());
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildAbout() {
|
||||||
|
return SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
buildItem(title: "Version", subtitle: App.version),
|
||||||
|
buildItem(
|
||||||
|
title: "Github",
|
||||||
|
action: IconButton(
|
||||||
|
icon: const Icon(MdIcons.open_in_new, size: 18,),
|
||||||
|
onPressed: () =>
|
||||||
|
launchUrlString("https://github.com/wgh136/pixes"),
|
||||||
|
)),
|
||||||
|
buildItem(
|
||||||
|
title: "Telegram",
|
||||||
|
action: IconButton(
|
||||||
|
icon: const Icon(MdIcons.open_in_new, size: 18,),
|
||||||
|
onPressed: () =>
|
||||||
|
launchUrlString("https://t.me/pica_group"),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SetDownloadPathPage extends StatefulWidget {
|
||||||
|
const _SetDownloadPathPage();
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_SetDownloadPathPage> createState() => __SetDownloadPathPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class __SetDownloadPathPageState extends State<_SetDownloadPathPage> {
|
||||||
|
final controller =
|
||||||
|
TextEditingController(text: appdata.settings["downloadPath"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TitleBar(title: "Download Path".tl),
|
||||||
|
TextBox(
|
||||||
|
controller: controller,
|
||||||
|
).paddingHorizontal(16),
|
||||||
|
const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
child: Text("Confirm".tl),
|
||||||
|
onPressed: () {
|
||||||
|
var text = controller.text;
|
||||||
|
if (Directory(text).havePermission()) {
|
||||||
|
appdata.settings["downloadPath"] = text;
|
||||||
|
appdata.writeData();
|
||||||
|
context.pop();
|
||||||
|
} else {
|
||||||
|
showToast(context, message: "No Permission".tl);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
).toAlign(Alignment.centerRight).paddingRight(16),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SetDownloadSubPathPage extends StatefulWidget {
|
||||||
|
const _SetDownloadSubPathPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_SetDownloadSubPathPage> createState() =>
|
||||||
|
__SetDownloadSubPathPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class __SetDownloadSubPathPageState extends State<_SetDownloadSubPathPage> {
|
||||||
|
final controller =
|
||||||
|
TextEditingController(text: appdata.settings["downloadSubPath"]);
|
||||||
|
final controller2 =
|
||||||
|
TextEditingController(text: appdata.settings["tagsWeight"]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TitleBar(title: "Download Subpath".tl),
|
||||||
|
Text("Rule".tl)
|
||||||
|
.padding(const EdgeInsets.symmetric(vertical: 8, horizontal: 16)),
|
||||||
|
TextBox(
|
||||||
|
controller: controller,
|
||||||
|
).paddingHorizontal(16),
|
||||||
|
Text("Weights of the tags".tl)
|
||||||
|
.padding(const EdgeInsets.symmetric(vertical: 8, horizontal: 16)),
|
||||||
|
TextBox(
|
||||||
|
controller: controller2,
|
||||||
|
).paddingHorizontal(16),
|
||||||
|
const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text("Use translated tag name".tl),
|
||||||
|
trailing: ToggleSwitch(
|
||||||
|
checked: appdata.settings["useTranslatedNameForDownload"],
|
||||||
|
onChanged: (value) {
|
||||||
|
appdata.settings["useTranslatedNameForDownload"] = value;
|
||||||
|
appdata.writeSettings();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
child: Text("Confirm".tl),
|
||||||
|
onPressed: () {
|
||||||
|
var text = controller.text;
|
||||||
|
if (check(text)) {
|
||||||
|
appdata.settings["downloadSubPath"] = text;
|
||||||
|
appdata.writeData();
|
||||||
|
context.pop();
|
||||||
|
} else {
|
||||||
|
showToast(context, message: "No Permission".tl);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
).toAlign(Alignment.centerRight).paddingRight(16),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
Text(_instruction).paddingHorizontal(16)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check(String text) {
|
||||||
|
if (!text.startsWith('/') || !text.startsWith('\\')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String get _instruction => """
|
||||||
|
${"Edit the rule of where to store a image.".tl}
|
||||||
|
${"Note: The rule should contain file name.".tl}
|
||||||
|
|
||||||
|
${"Some keyword will be replaced as following rule:"}
|
||||||
|
\${title} -> ${"Title of the actwork".tl}
|
||||||
|
\${author} -> ${"Name of the author".tl}
|
||||||
|
\${id} -> ${"Actwork ID".tl}
|
||||||
|
\${index} -> ${"Index of the image in the artwork".tl}
|
||||||
|
\${ext} -> ${"File extension".tl}
|
||||||
|
${"Tags: Tags will be sorted with \"Weights of tags\" setting and be replaced with following rule".tl}
|
||||||
|
${"The final text will be affect by the setting og \"Use translated tag name\"".tl}
|
||||||
|
\${tag0} -> ${"The first tag of the artwork".tl}
|
||||||
|
\${tag1} -> ${"The sencondary tag of the artwork".tl}
|
||||||
|
|
||||||
|
${"Weights of the tags".tl}:
|
||||||
|
Filled with tags. The tags should be splited with a space. The tag in the front have higher weight.
|
||||||
|
It is required to use originlal name instead of translated name.
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user