Improve config updates check

This commit is contained in:
2025-01-18 15:43:22 +08:00
parent 481bb97301
commit 16512f2711
7 changed files with 133 additions and 43 deletions

View File

@@ -315,7 +315,10 @@
"Tags": "标签", "Tags": "标签",
"Authors": "作者", "Authors": "作者",
"Comics": "漫画", "Comics": "漫画",
"Imported @a comics": "已导入 @a 本漫画" "Imported @a comics": "已导入 @a 本漫画",
"New Version": "新版本",
"@c updates": "@c 项更新",
"No updates": "无更新"
}, },
"zh_TW": { "zh_TW": {
"Home": "首頁", "Home": "首頁",
@@ -633,6 +636,9 @@
"Tags": "標籤", "Tags": "標籤",
"Authors": "作者", "Authors": "作者",
"Comics": "漫畫", "Comics": "漫畫",
"Imported @a comics": "已匯入 @a 部漫畫" "Imported @a comics": "已匯入 @a 部漫畫",
"New Version": "新版本",
"@c updates": "@c 項更新",
"No updates": "無更新"
} }
} }

View File

@@ -136,6 +136,8 @@ class ComicSource {
notifyListeners(); notifyListeners();
} }
static final availableUpdates = <String, String>{};
static bool get isEmpty => _sources.isEmpty; static bool get isEmpty => _sources.isEmpty;
/// Name of this source. /// Name of this source.

View File

@@ -1,5 +1,6 @@
part of 'comic_source.dart'; part of 'comic_source.dart';
/// return true if ver1 > ver2
bool compareSemVer(String ver1, String ver2) { bool compareSemVer(String ver1, String ver2) {
ver1 = ver1.replaceFirst("-", "."); ver1 = ver1.replaceFirst("-", ".");
ver2 = ver2.replaceFirst("-", "."); ver2 = ver2.replaceFirst("-", ".");

View File

@@ -14,17 +14,15 @@ import 'package:venera/utils/translations.dart';
class ComicSourcePage extends StatefulWidget { class ComicSourcePage extends StatefulWidget {
const ComicSourcePage({super.key}); const ComicSourcePage({super.key});
static Future<void> checkComicSourceUpdate([bool implicit = false]) async { static Future<int> checkComicSourceUpdate() async {
if (ComicSource.all().isEmpty) { if (ComicSource.all().isEmpty) {
return; return 0;
} }
var controller = implicit ? null : showLoadingDialog(App.rootContext);
var dio = AppDio(); var dio = AppDio();
var res = await dio.get<String>( var res = await dio.get<String>(
"https://raw.githubusercontent.com/venera-app/venera-configs/master/index.json"); "https://raw.githubusercontent.com/venera-app/venera-configs/master/index.json");
if (res.statusCode != 200) { if (res.statusCode != 200) {
App.rootContext.showMessage(message: "Network error".tl); return -1;
return;
} }
var list = jsonDecode(res.data!) as List; var list = jsonDecode(res.data!) as List;
var versions = <String, String>{}; var versions = <String, String>{};
@@ -34,34 +32,17 @@ class ComicSourcePage extends StatefulWidget {
var shouldUpdate = <String>[]; var shouldUpdate = <String>[];
for (var source in ComicSource.all()) { for (var source in ComicSource.all()) {
if (versions.containsKey(source.key) && if (versions.containsKey(source.key) &&
versions[source.key] != source.version) { compareSemVer(versions[source.key]!, source.version)) {
shouldUpdate.add(source.key); shouldUpdate.add(source.key);
} }
} }
controller?.close(); if (shouldUpdate.isNotEmpty) {
if (shouldUpdate.isEmpty) {
if (!implicit) {
App.rootContext.showMessage(message: "No Update Available".tl);
}
return;
}
var msg = "";
for (var key in shouldUpdate) { for (var key in shouldUpdate) {
msg += "${ComicSource.find(key)?.name}: v${versions[key]}\n"; ComicSource.availableUpdates[key] = versions[key]!;
} }
msg = msg.trim(); ComicSource.notifyListeners();
await showConfirmDialog(
context: App.rootContext,
title: "Updates Available".tl,
content: msg,
confirmText: "Update",
onConfirm: () async {
for (var key in shouldUpdate) {
var source = ComicSource.find(key);
await _BodyState.update(source!);
} }
}, return shouldUpdate.length;
);
} }
@override @override
@@ -90,6 +71,22 @@ class _Body extends StatefulWidget {
class _BodyState extends State<_Body> { class _BodyState extends State<_Body> {
var url = ""; var url = "";
void updateUI() {
setState(() {});
}
@override
void initState() {
super.initState();
ComicSource.addListener(updateUI);
}
@override
void dispose() {
super.dispose();
ComicSource.removeListener(updateUI);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SmoothCustomScrollView( return SmoothCustomScrollView(
@@ -102,12 +99,36 @@ class _BodyState extends State<_Body> {
} }
Widget buildSource(BuildContext context, ComicSource source) { Widget buildSource(BuildContext context, ComicSource source) {
var newVersion = ComicSource.availableUpdates[source.key];
bool hasUpdate =
newVersion != null && compareSemVer(newVersion, source.version);
return SliverToBoxAdapter( return SliverToBoxAdapter(
child: Column( child: Column(
children: [ children: [
const Divider(), const Divider(),
ListTile( ListTile(
title: Text(source.name), title: Row(
children: [
Text(source.name),
const SizedBox(width: 6),
if (hasUpdate)
Tooltip(
message: newVersion,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: context.colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
),
child: Text(
"New Version".tl,
style: const TextStyle(fontSize: 13),
),
),
)
],
),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -299,6 +320,9 @@ class _BodyState extends State<_Body> {
controller.close(); controller.close();
await ComicSourceParser().parse(res.data!, source.filePath); await ComicSourceParser().parse(res.data!, source.filePath);
await File(source.filePath).writeAsString(res.data!); await File(source.filePath).writeAsString(res.data!);
if (ComicSource.availableUpdates.containsKey(source.key)) {
ComicSource.availableUpdates.remove(source.key);
}
} catch (e) { } catch (e) {
if (cancel) return; if (cancel) return;
App.rootContext.showMessage(message: e.toString()); App.rootContext.showMessage(message: e.toString());
@@ -368,10 +392,7 @@ class _BodyState extends State<_Body> {
), ),
ListTile( ListTile(
title: Text("Check updates".tl), title: Text("Check updates".tl),
trailing: buildButton( trailing: _CheckUpdatesButton(),
onPressed: () => ComicSourcePage.checkComicSourceUpdate(false),
child: Text("Check".tl),
),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
], ],
@@ -619,3 +640,40 @@ class __EditFilePageState extends State<_EditFilePage> {
); );
} }
} }
class _CheckUpdatesButton extends StatefulWidget {
const _CheckUpdatesButton();
@override
State<_CheckUpdatesButton> createState() => _CheckUpdatesButtonState();
}
class _CheckUpdatesButtonState extends State<_CheckUpdatesButton> {
bool isLoading = false;
void check() async {
setState(() {
isLoading = true;
});
var count = await ComicSourcePage.checkComicSourceUpdate();
if (count == -1) {
context.showMessage(message: "Network error".tl);
} else if (count == 0) {
context.showMessage(message: "No updates".tl);
} else {
context.showMessage(message: "@c updates".tlParams({"c": count}));
}
setState(() {
isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return Button.normal(
onPressed: check,
isLoading: isLoading,
child: Text("Check".tl),
).fixHeight(32);
}
}

View File

@@ -696,6 +696,30 @@ class _ComicSourceWidgetState extends State<_ComicSourceWidget> {
}).toList(), }).toList(),
).paddingHorizontal(16).paddingBottom(16), ).paddingHorizontal(16).paddingBottom(16),
), ),
if (ComicSource.availableUpdates.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
border: Border.all(
color: context.colorScheme.outlineVariant,
width: 0.6,
),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.update, color: context.colorScheme.primary, size: 20,),
const SizedBox(width: 8),
Text("@c updates".tlParams({
'c': ComicSource.availableUpdates.length,
}), style: ts.withColor(context.colorScheme.primary),),
],
),
).toAlign(Alignment.centerLeft).paddingHorizontal(16).paddingBottom(8),
], ],
), ),
), ),

View File

@@ -37,9 +37,6 @@ class _MainPageState extends State<MainPage> {
} }
void checkUpdates() async { void checkUpdates() async {
if (!appdata.settings['checkUpdateOnStart']) {
return;
}
var lastCheck = appdata.implicitData['lastCheckUpdate'] ?? 0; var lastCheck = appdata.implicitData['lastCheckUpdate'] ?? 0;
var now = DateTime.now().millisecondsSinceEpoch; var now = DateTime.now().millisecondsSinceEpoch;
if (now - lastCheck < 24 * 60 * 60 * 1000) { if (now - lastCheck < 24 * 60 * 60 * 1000) {
@@ -47,9 +44,11 @@ class _MainPageState extends State<MainPage> {
} }
appdata.implicitData['lastCheckUpdate'] = now; appdata.implicitData['lastCheckUpdate'] = now;
appdata.writeImplicitData(); appdata.writeImplicitData();
ComicSourcePage.checkComicSourceUpdate();
if (appdata.settings['checkUpdateOnStart']) {
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
await checkUpdateUi(false); await checkUpdateUi(false);
await ComicSourcePage.checkComicSourceUpdate(true); }
} }
@override @override

View File

@@ -307,8 +307,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "841ef5f77e5fdfd79e3eb2fa07ece4d46787285b" ref: b33344797f1d2469339e0e1b75f5f954f1da224c
resolved-ref: "841ef5f77e5fdfd79e3eb2fa07ece4d46787285b" resolved-ref: b33344797f1d2469339e0e1b75f5f954f1da224c
url: "https://github.com/wgh136/flutter_7zip" url: "https://github.com/wgh136/flutter_7zip"
source: git source: git
version: "0.0.1" version: "0.0.1"