opt.: auto add date for manual webdav backup

This commit is contained in:
lollipopkit
2024-01-11 18:37:57 +08:00
parent 7032677def
commit 460f3f957e
7 changed files with 93 additions and 40 deletions

View File

@@ -586,7 +586,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -596,7 +596,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -720,7 +720,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -730,7 +730,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -748,7 +748,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -758,7 +758,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -779,7 +779,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -792,7 +792,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
@@ -818,7 +818,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -831,7 +831,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -854,7 +854,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -867,7 +867,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -890,7 +890,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -902,7 +902,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
@@ -931,7 +931,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -943,7 +943,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
PRODUCT_NAME = ServerBox; PRODUCT_NAME = ServerBox;
@@ -969,7 +969,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 700; CURRENT_PROJECT_VERSION = 701;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -981,7 +981,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.700; MARKETING_VERSION = 1.0.701;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
PRODUCT_NAME = ServerBox; PRODUCT_NAME = ServerBox;

View File

@@ -2,4 +2,14 @@ extension DateTimeX on DateTime {
String get hourMinute { String get hourMinute {
return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}'; return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}';
} }
/// Format: 2021-01-01-0000
String get numStr {
final year = this.year.toString();
final month = this.month.toString().padLeft(2, '0');
final day = this.day.toString().padLeft(2, '0');
final hour = this.hour.toString().padLeft(2, '0');
final minute = this.minute.toString().padLeft(2, '0');
return '$year-$month-$day-$hour$minute';
}
} }

View File

@@ -73,6 +73,21 @@ abstract final class Webdav {
return null; return null;
} }
static Future<List<String>> list() async {
try {
final list = await _client.readDir(_prefix);
final names = <String>[];
for (final item in list) {
if ((item.isDir ?? true) || item.name == null) continue;
names.add(item.name!);
}
return names;
} catch (e, s) {
_logger.warning('List failed', e, s);
return [];
}
}
static void changeClient(String url, String user, String pwd) { static void changeClient(String url, String user, String pwd) {
_client = WebdavClient(url: url, user: user, pwd: pwd); _client = WebdavClient(url: url, user: user, pwd: pwd);
Stores.setting.webdavUrl.put(url); Stores.setting.webdavUrl.put(url);

View File

@@ -76,9 +76,9 @@ class Backup {
lastModTime = Stores.lastModTime, lastModTime = Stores.lastModTime,
history = Stores.history.box.toJson(); history = Stores.history.box.toJson();
static Future<String> backup() async { static Future<String> backup([String? name]) async {
final result = _diyEncrypt(json.encode(Backup.loadFromStore())); final result = _diyEncrypt(json.encode(Backup.loadFromStore()));
final path = await Paths.bak; final path = '${await Paths.doc}/${name ?? Paths.bakName}';
await File(path).writeAsString(result); await File(path).writeAsString(result);
return path; return path;
} }

View File

@@ -2,9 +2,9 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 700; static const int build = 701;
static const String engine = "3.16.5"; static const String engine = "3.16.5";
static const String buildAt = "2024-01-06 11:00:48"; static const String buildAt = "2024-01-06 13:39:30";
static const int modifications = 4; static const int modifications = 1;
static const int script = 34; static const int script = 34;
} }

View File

@@ -6,6 +6,7 @@ import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/datetime.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
import 'package:toolbox/core/utils/sync/icloud.dart'; import 'package:toolbox/core/utils/sync/icloud.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
@@ -122,8 +123,7 @@ class BackupPage extends StatelessWidget {
child: ExpandTile( child: ExpandTile(
leading: const Icon(Icons.storage), leading: const Icon(Icons.storage),
title: const Text('WebDAV'), title: const Text('WebDAV'),
initiallyExpanded: initiallyExpanded: true,
!(isIOS || isMacOS) && Stores.setting.webdavSync.fetch(),
children: [ children: [
ListTile( ListTile(
title: Text(l10n.setting), title: Text(l10n.setting),
@@ -241,21 +241,48 @@ class BackupPage extends StatelessWidget {
Future<void> _onTapWebdavDl(BuildContext context) async { Future<void> _onTapWebdavDl(BuildContext context) async {
webdavLoading.value = true; webdavLoading.value = true;
try { final files = await Webdav.list();
final result = await Webdav.download( if (files.isEmpty) {
relativePath: Paths.bakName, context.showSnackBar(l10n.dirEmpty);
);
if (result != null) {
Loggers.app.warning('Download webdav backup failed: $result');
return;
}
} catch (e, s) {
Loggers.app.warning('Download webdav backup failed', e, s);
context.showSnackBar(e.toString());
webdavLoading.value = false; webdavLoading.value = false;
return; return;
} }
final dlFile = await File(await Paths.bak).readAsString();
final fileName = await context.showRoundDialog<String>(
title: Text(l10n.restore),
child: SizedBox(
width: 300,
height: 300,
child: ListView.builder(
itemCount: files.length,
itemBuilder: (_, index) {
final file = files[index];
return ListTile(
title: Text(file),
onTap: () => context.pop(file),
);
},
),
),
actions: [
TextButton(
onPressed: () => context.pop(),
child: Text(l10n.cancel),
),
],
);
if (fileName == null) {
webdavLoading.value = false;
return;
}
final result = await Webdav.download(relativePath: fileName);
if (result != null) {
Loggers.app.warning('Download webdav backup failed: $result');
webdavLoading.value = false;
return;
}
final dlFile = await File(fileName).readAsString();
final dlBak = await compute(Backup.fromJsonString, dlFile); final dlBak = await compute(Backup.fromJsonString, dlFile);
await dlBak.restore(force: true); await dlBak.restore(force: true);
webdavLoading.value = false; webdavLoading.value = false;
@@ -263,8 +290,9 @@ class BackupPage extends StatelessWidget {
Future<void> _onTapWebdavUp(BuildContext context) async { Future<void> _onTapWebdavUp(BuildContext context) async {
webdavLoading.value = true; webdavLoading.value = true;
await Backup.backup(); final bakName = '${DateTime.now().numStr}-${Paths.bakName}';
final uploadResult = await Webdav.upload(relativePath: Paths.bakName); await Backup.backup(bakName);
final uploadResult = await Webdav.upload(relativePath: bakName);
if (uploadResult != null) { if (uploadResult != null) {
Loggers.app.warning('Upload webdav backup failed: $uploadResult'); Loggers.app.warning('Upload webdav backup failed: $uploadResult');
} else { } else {

View File

@@ -59,7 +59,7 @@ class _InputState extends State<Input> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CardX( return CardX(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 7), padding: const EdgeInsets.symmetric(horizontal: 15),
child: TextField( child: TextField(
controller: widget.controller, controller: widget.controller,
maxLines: widget.maxLines, maxLines: widget.maxLines,