Merge pull request #17 from venera-app/dev

v1.0.2
This commit is contained in:
nyne
2024-11-05 22:55:32 +08:00
committed by GitHub
29 changed files with 905 additions and 157 deletions

View File

@@ -1576,7 +1576,7 @@ class _SelectDownloadChapterState extends State<_SelectDownloadChapter> {
const SizedBox(width: 16),
Expanded(
child: FilledButton(
onPressed: () {
onPressed: selected.isEmpty ? null : () {
widget.finishSelect(selected);
context.pop();
},
@@ -1587,7 +1587,7 @@ class _SelectDownloadChapterState extends State<_SelectDownloadChapter> {
],
),
),
SizedBox(height: MediaQuery.of(context).padding.bottom + 4),
SizedBox(height: MediaQuery.of(context).padding.bottom),
],
),
);

View File

@@ -14,11 +14,11 @@ import 'package:venera/utils/translations.dart';
class ComicSourcePage extends StatefulWidget {
const ComicSourcePage({super.key});
static void checkComicSourceUpdate([bool showLoading = false]) async {
static Future<void> checkComicSourceUpdate([bool implicit = false]) async {
if (ComicSource.all().isEmpty) {
return;
}
var controller = showLoading ? showLoadingDialog(App.rootContext) : null;
var controller = implicit ? null : showLoadingDialog(App.rootContext);
var dio = AppDio();
var res = await dio.get<String>(
"https://raw.githubusercontent.com/venera-app/venera-configs/master/index.json");
@@ -40,7 +40,9 @@ class ComicSourcePage extends StatefulWidget {
}
controller?.close();
if (shouldUpdate.isEmpty) {
App.rootContext.showMessage(message: "No Update Available".tl);
if(!implicit) {
App.rootContext.showMessage(message: "No Update Available".tl);
}
return;
}
var msg = "";
@@ -48,10 +50,11 @@ class ComicSourcePage extends StatefulWidget {
msg += "${ComicSource.find(key)?.name}: v${versions[key]}\n";
}
msg = msg.trim();
showConfirmDialog(
await showConfirmDialog(
context: App.rootContext,
title: "Updates Available".tl,
content: msg,
confirmText: "Update",
onConfirm: () {
for (var key in shouldUpdate) {
var source = ComicSource.find(key);
@@ -104,7 +107,7 @@ class _BodyState extends State<_Body> {
child: ListTile(
leading: const Icon(Icons.update_outlined),
title: Text("Check updates".tl),
onTap: () => ComicSourcePage.checkComicSourceUpdate(true),
onTap: () => ComicSourcePage.checkComicSourceUpdate(false),
trailing: const Icon(Icons.arrow_right),
),
);
@@ -161,71 +164,76 @@ class _BodyState extends State<_Body> {
for (var item in source.settings!.entries) {
var key = item.key;
String type = item.value['type'];
if (type == "select") {
var current = source.data['settings'][key];
if (current == null) {
var d = item.value['default'];
for (var option in item.value['options']) {
if (option['value'] == d) {
current = option['text'] ?? option['value'];
break;
try {
if (type == "select") {
var current = source.data['settings'][key];
if (current == null) {
var d = item.value['default'];
for (var option in item.value['options']) {
if (option['value'] == d) {
current = option['text'] ?? option['value'];
break;
}
}
}
yield ListTile(
title: Text((item.value['title'] as String).ts(source.key)),
trailing: Select(
current: (current as String).ts(source.key),
values: (item.value['options'] as List)
.map<String>(
(e) => ((e['text'] ?? e['value']) as String).ts(source.key))
.toList(),
onTap: (i) {
source.data['settings'][key] = item.value['options'][i]['value'];
source.saveData();
setState(() {});
},
),
);
} else if (type == "switch") {
var current = source.data['settings'][key] ?? item.value['default'];
yield ListTile(
title: Text((item.value['title'] as String).ts(source.key)),
trailing: Switch(
value: current,
onChanged: (v) {
source.data['settings'][key] = v;
source.saveData();
setState(() {});
},
),
);
} else if (type == "input") {
var current =
source.data['settings'][key] ?? item.value['default'] ?? '';
yield ListTile(
title: Text((item.value['title'] as String).ts(source.key)),
subtitle: Text(current, maxLines: 1, overflow: TextOverflow.ellipsis),
trailing: IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
showInputDialog(
context: context,
title: (item.value['title'] as String).ts(source.key),
initialValue: current,
inputValidator: item.value['validator'] == null
? null
: RegExp(item.value['validator']),
onConfirm: (value) {
source.data['settings'][key] = value;
source.saveData();
setState(() {});
return null;
},
);
},
),
);
}
yield ListTile(
title: Text((item.value['title'] as String).ts(source.key)),
trailing: Select(
current: (current as String).ts(source.key),
values: (item.value['options'] as List)
.map<String>(
(e) => ((e['text'] ?? e['value']) as String).ts(source.key))
.toList(),
onTap: (i) {
source.data['settings'][key] = item.value['options'][i]['value'];
source.saveData();
setState(() {});
},
),
);
} else if (type == "switch") {
var current = source.data['settings'][key] ?? item.value['default'];
yield ListTile(
title: Text((item.value['title'] as String).ts(source.key)),
trailing: Switch(
value: current,
onChanged: (v) {
source.data['settings'][key] = v;
source.saveData();
setState(() {});
},
),
);
} else if (type == "input") {
var current =
source.data['settings'][key] ?? item.value['default'] ?? '';
yield ListTile(
title: Text((item.value['title'] as String).ts(source.key)),
subtitle: Text(current, maxLines: 1, overflow: TextOverflow.ellipsis),
trailing: IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
showInputDialog(
context: context,
title: (item.value['title'] as String).ts(source.key),
initialValue: current,
inputValidator: item.value['validator'] == null
? null
: RegExp(item.value['validator']),
onConfirm: (value) {
source.data['settings'][key] = value;
source.saveData();
setState(() {});
return null;
},
);
},
),
);
}
catch(e, s) {
Log.error("ComicSourcePage", "Failed to build a setting\n$e\n$s");
}
}
}
@@ -446,10 +454,11 @@ class _ComicSourceListState extends State<_ComicSourceList> {
itemBuilder: (context, index) {
var key = json![index]["key"];
var action = currentKey.contains(key)
? const Icon(Icons.check)
? const Icon(Icons.check, size: 20).paddingRight(8)
: Tooltip(
message: "Add",
child: IconButton(
child: Button.icon(
color: context.colorScheme.primary,
icon: const Icon(Icons.add),
onPressed: () async {
await widget.onAdd(

View File

@@ -223,6 +223,9 @@ class _GalleryModeState extends State<_GalleryMode>
@override
void handleLongPressDown(Offset location) {
if(!appdata.settings['enableLongPressToZoom']) {
return;
}
var photoViewController = photoViewControllers[reader.page]!;
double target = photoViewController.getInitialScale!.call()! * 1.75;
var size = MediaQuery.of(context).size;
@@ -234,6 +237,9 @@ class _GalleryModeState extends State<_GalleryMode>
@override
void handleLongPressUp(Offset location) {
if(!appdata.settings['enableLongPressToZoom']) {
return;
}
var photoViewController = photoViewControllers[reader.page]!;
double target = photoViewController.getInitialScale!.call()!;
photoViewController.animateScale?.call(target);
@@ -509,6 +515,9 @@ class _ContinuousModeState extends State<_ContinuousMode>
@override
void handleLongPressDown(Offset location) {
if(!appdata.settings['enableLongPressToZoom']) {
return;
}
double target = photoViewController.getInitialScale!.call()! * 1.75;
var size = MediaQuery.of(context).size;
photoViewController.animateScale?.call(
@@ -519,6 +528,9 @@ class _ContinuousModeState extends State<_ContinuousMode>
@override
void handleLongPressUp(Offset location) {
if(!appdata.settings['enableLongPressToZoom']) {
return;
}
double target = photoViewController.getInitialScale!.call()!;
photoViewController.animateScale?.call(target);
}

View File

@@ -393,7 +393,7 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> {
Widget buildPageInfoText() {
var epName = context.reader.widget.chapters?.values
.elementAt(context.reader.chapter - 1) ??
.elementAtOrNull(context.reader.chapter - 1) ??
"E${context.reader.chapter}";
if (epName.length > 8) {
epName = "${epName.substring(0, 8)}...";

View File

@@ -53,30 +53,7 @@ class _AboutSettingsState extends State<AboutSettings> {
setState(() {
isCheckingUpdate = true;
});
checkUpdate().then((value) {
if (value) {
showDialog(
context: App.rootContext,
builder: (context) {
return ContentDialog(
title: "New version available".tl,
content: Text(
"A new version is available. Do you want to update now?"
.tl),
actions: [
Button.text(
onPressed: () {
Navigator.pop(context);
launchUrlString(
"https://github.com/venera-app/venera/releases");
},
child: Text("Update".tl),
),
]);
});
} else {
context.showMessage(message: "No new version available".tl);
}
checkUpdateUi().then((value) {
setState(() {
isCheckingUpdate = false;
});
@@ -108,6 +85,33 @@ Future<bool> checkUpdate() async {
return false;
}
Future<void> checkUpdateUi([bool showMessageIfNoUpdate = true]) async {
var value = await checkUpdate();
if (value) {
showDialog(
context: App.rootContext,
builder: (context) {
return ContentDialog(
title: "New version available".tl,
content: Text(
"A new version is available. Do you want to update now?".tl),
actions: [
Button.text(
onPressed: () {
Navigator.pop(context);
launchUrlString(
"https://github.com/venera-app/venera/releases");
},
child: Text("Update".tl),
),
],
);
});
} else if (showMessageIfNoUpdate) {
App.rootContext.showMessage(message: "No new version available".tl);
}
}
/// return true if version1 > version2
bool _compareVersion(String version1, String version2) {
var v1 = version1.split(".");

View File

@@ -17,6 +17,13 @@ class _NetworkSettingsState extends State<NetworkSettings> {
title: "Proxy".tl,
builder: () => const _ProxySettingView(),
).toSliver(),
_SliderSetting(
title: "Download Threads".tl,
settingsIndex: 'downloadThreads',
interval: 1,
min: 1,
max: 16,
).toSliver(),
],
);
}
@@ -42,50 +49,50 @@ class _ProxySettingViewState extends State<_ProxySettingView> {
// USERNAME:PASSWORD@HOST:PORT
String toProxyStr() {
if(type == 'direct') {
if (type == 'direct') {
return 'direct';
} else if(type == 'system') {
} else if (type == 'system') {
return 'system';
}
var res = '';
if(username.isNotEmpty) {
if (username.isNotEmpty) {
res += username;
if(password.isNotEmpty) {
if (password.isNotEmpty) {
res += ':$password';
}
res += '@';
}
res += host;
if(port.isNotEmpty) {
if (port.isNotEmpty) {
res += ':$port';
}
return res;
}
void parseProxyString(String proxy) {
if(proxy == 'direct') {
if (proxy == 'direct') {
type = 'direct';
return;
} else if(proxy == 'system') {
} else if (proxy == 'system') {
type = 'system';
return;
}
type = 'manual';
var parts = proxy.split('@');
if(parts.length == 2) {
if (parts.length == 2) {
var auth = parts[0].split(':');
if(auth.length == 2) {
if (auth.length == 2) {
username = auth[0];
password = auth[1];
}
parts = parts[1].split(':');
if(parts.length == 2) {
if (parts.length == 2) {
host = parts[0];
port = parts[1];
}
} else {
parts = proxy.split(':');
if(parts.length == 2) {
if (parts.length == 2) {
host = parts[0];
port = parts[1];
}
@@ -140,7 +147,7 @@ class _ProxySettingViewState extends State<_ProxySettingView> {
});
},
),
if(type == 'manual') buildManualProxy(),
if (type == 'manual') buildManualProxy(),
],
),
),
@@ -164,7 +171,7 @@ class _ProxySettingViewState extends State<_ProxySettingView> {
host = v;
},
validator: (v) {
if(v?.isEmpty ?? false) {
if (v?.isEmpty ?? false) {
return "Host cannot be empty".tl;
}
return null;
@@ -181,10 +188,10 @@ class _ProxySettingViewState extends State<_ProxySettingView> {
port = v;
},
validator: (v) {
if(v?.isEmpty ?? true) {
if (v?.isEmpty ?? true) {
return null;
}
if(int.tryParse(v!) == null) {
if (int.tryParse(v!) == null) {
return "Port must be a number".tl;
}
return null;
@@ -201,7 +208,7 @@ class _ProxySettingViewState extends State<_ProxySettingView> {
username = v;
},
validator: (v) {
if((v?.isEmpty ?? false) && password.isNotEmpty) {
if ((v?.isEmpty ?? false) && password.isNotEmpty) {
return "Username cannot be empty".tl;
}
return null;
@@ -221,7 +228,7 @@ class _ProxySettingViewState extends State<_ProxySettingView> {
const SizedBox(height: 16),
FilledButton(
onPressed: () {
if(formKey.currentState?.validate() ?? false) {
if (formKey.currentState?.validate() ?? false) {
appdata.settings['proxy'] = toProxyStr();
appdata.saveData();
App.rootContext.pop();

View File

@@ -54,6 +54,13 @@ class _ReaderSettingsState extends State<ReaderSettings> {
widget.onChanged?.call("autoPageTurningInterval");
},
).toSliver(),
_SwitchSetting(
title: 'Long press to zoom'.tl,
settingKey: 'enableLongPressToZoom',
onChanged: () {
widget.onChanged?.call('enableLongPressToZoom');
},
).toSliver(),
],
);
}