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,
|
||||
};
|
||||
|
||||
bool lock = false;
|
||||
|
||||
void writeData() async {
|
||||
while (lock) {
|
||||
await Future.delayed(const Duration(milliseconds: 20));
|
||||
}
|
||||
lock = true;
|
||||
await File("${App.dataPath}/account.json")
|
||||
.writeAsString(jsonEncode(account));
|
||||
await File("${App.dataPath}/settings.json")
|
||||
.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 {
|
||||
@@ -35,17 +52,17 @@ class _Appdata {
|
||||
final settingsFile = File("${App.dataPath}/settings.json");
|
||||
if (settingsFile.existsSync()) {
|
||||
var json = jsonDecode(await settingsFile.readAsString());
|
||||
for(var key in json.keys) {
|
||||
for (var key in json.keys) {
|
||||
settings[key] = json[key];
|
||||
}
|
||||
}
|
||||
if(settings["downloadPath"] == null) {
|
||||
if (settings["downloadPath"] == null) {
|
||||
settings["downloadPath"] = await _defaultDownloadPath;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> get _defaultDownloadPath async{
|
||||
if(App.isAndroid) {
|
||||
Future<String> get _defaultDownloadPath async {
|
||||
if (App.isAndroid) {
|
||||
String? downloadPath = "/storage/emulated/0/download";
|
||||
if (!Directory(downloadPath).havePermission()) {
|
||||
downloadPath = null;
|
||||
@@ -53,14 +70,15 @@ class _Appdata {
|
||||
var res = downloadPath;
|
||||
res ??= (await getExternalStorageDirectory())!.path;
|
||||
return "$res/pixes";
|
||||
} else if (App.isWindows){
|
||||
var res = await const MethodChannel("pixes/picture_folder").invokeMethod("");
|
||||
if(res != "error") {
|
||||
} else if (App.isWindows) {
|
||||
var res =
|
||||
await const MethodChannel("pixes/picture_folder").invokeMethod("");
|
||||
if (res != "error") {
|
||||
return res + "/pixes";
|
||||
}
|
||||
} else if (App.isMacOS || App.isLinux) {
|
||||
var downloadPath = (await getDownloadsDirectory())?.path;
|
||||
if(downloadPath != null && Directory(downloadPath).havePermission()) {
|
||||
if (downloadPath != null && Directory(downloadPath).havePermission()) {
|
||||
return "$downloadPath/pixes";
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@ export "state_controller.dart";
|
||||
export "navigation.dart";
|
||||
|
||||
class _App {
|
||||
final version = "1.0.0";
|
||||
|
||||
bool get isAndroid => Platform.isAndroid;
|
||||
bool get isIOS => Platform.isIOS;
|
||||
bool get isWindows => Platform.isWindows;
|
||||
|
@@ -114,11 +114,15 @@ class DownloadingTask {
|
||||
static String _generateFilePath(Illust illust, int index, String ext) {
|
||||
final String downloadPath = appdata.settings["downloadPath"];
|
||||
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(' ');
|
||||
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"${title}", illust.title);
|
||||
subPathPatten = subPathPatten.replaceAll(r"${author}", illust.author.name);
|
||||
|
@@ -106,7 +106,14 @@ class Network {
|
||||
},
|
||||
options: Options(
|
||||
contentType: Headers.formUrlEncodedContentType,
|
||||
validateStatus: (i) => true,
|
||||
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!));
|
||||
appdata.account = account;
|
||||
appdata.writeData();
|
||||
|
@@ -1,9 +1,14 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.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/title_bar.dart';
|
||||
import 'package:pixes/foundation/app.dart';
|
||||
import 'package:pixes/pages/main_page.dart';
|
||||
import 'package:pixes/utils/io.dart';
|
||||
import 'package:pixes/utils/translation.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
@@ -24,7 +29,12 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
SliverTitleBar(title: "Settings".tl),
|
||||
buildHeader("Account".tl),
|
||||
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(
|
||||
child: Padding(
|
||||
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}) {
|
||||
@@ -49,8 +61,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildAccount(){
|
||||
|
||||
Widget buildAccount() {
|
||||
return SliverToBoxAdapter(
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -71,8 +83,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
App.rootNavigatorKey.currentState!.pushAndRemoveUntil(
|
||||
AppPageRoute(
|
||||
builder: (context) => const MainPage()),
|
||||
(route) => false
|
||||
);
|
||||
(route) => false);
|
||||
},
|
||||
),
|
||||
FilledButton(
|
||||
@@ -86,14 +97,209 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
child: Text("Continue".tl).fixWidth(64),
|
||||
),
|
||||
),
|
||||
buildItem(title: "Account Settings".tl, action: Button(
|
||||
child: Text("Edit".tl).fixWidth(64),
|
||||
onPressed: (){
|
||||
launchUrlString("https://www.pixiv.net/setting_user.php");
|
||||
},
|
||||
)),
|
||||
buildItem(
|
||||
title: "Account Settings".tl,
|
||||
action: Button(
|
||||
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