opt.: backup

This commit is contained in:
lollipopkit
2024-06-04 22:33:59 +08:00
parent 6dc5536c48
commit 413c45a559
4 changed files with 55 additions and 141 deletions

View File

@@ -30,7 +30,7 @@ jobs:
- name: Build - name: Build
run: dart run fl_build -p android,linux run: dart run fl_build -p android,linux
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v2
with: with:
files: | files: |
build/app/outputs/flutter-apk/${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_arm64.apk build/app/outputs/flutter-apk/${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_arm64.apk
@@ -53,7 +53,7 @@ jobs:
- name: Build - name: Build
run: dart run fl_build -p windows run: dart run fl_build -p windows
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v2
with: with:
files: | files: |
${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_windows_amd64.zip ${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_windows_amd64.zip
@@ -71,7 +71,7 @@ jobs:
# - name: Build # - name: Build
# run: dart run fl_build -p ios,mac # run: dart run fl_build -p ios,mac
# - name: Create Release # - name: Create Release
# uses: softprops/action-gh-release@v1 # uses: softprops/action-gh-release@v2
# with: # with:
# files: | # files: |
# ${{ env.APP_NAME }}_universal_macos.zip # ${{ env.APP_NAME }}_universal_macos.zip

View File

@@ -21,39 +21,24 @@ Especially thanks to <a href="https://github.com/TerminalStudio/dartssh2">dartss
## 🔖 Feature ## 🔖 Feature
- Status chart, `SSH` Terminal, `SFTP`, `Docker & Pkg & Process`, Code editor... - `Status chart` (CPU, Sensors, GPU...), `SSH` Term, `SFTP`, `Docker & Pkg & Process`...
- Platform specific: `Bio auth``Msg push``Home widget``watchOS App`... - Platform specific: `Bio auth``Msg push``Home widget``watchOS App`...
- Localization - English, 简体中文; Deutsch [@its-tom](https://github.com/its-tom), 繁體中文 [@kalashnikov](https://github.com/kalashnikov), Indonesian [@azkadev](https://github.com/azkadev), Français [@FrancXPT](https://github.com/FrancXPT), Dutch [@QazCetelic](https://github.com/QazCetelic); Español, Русский язык, Português, 日本語 (Generated by GPT)
- English, 简体中文
- Español, Русский язык, Português, 日本語 (Generated by GPT)
- Deutsch (@its-tom) / 繁體中文 (@kalashnikov) / Indonesian (@azkadev) / Français (@FrancXPT) / Dutch (@QazCetelic)
## 🏙️ ScreenShots ## 🏙️ ScreenShots
<table> <table>
<tr> <tr>
<td> <td><img width="277px" src="imgs/server.png"></td>
<img width="277px" src="imgs/server.png"> <td><img width="277px" src="imgs/detail.png"></td>
</td> <td><img width="277px" src="imgs/sftp.png"></td>
<td>
<img width="277px" src="imgs/detail.png">
</td>
<td>
<img width="277px" src="imgs/sftp.png">
</td>
</tr> </tr>
</table> </table>
<table> <table>
<tr> <tr>
<td> <td><img width="277px" src="imgs/editor.png"> </td>
<img width="277px" src="imgs/editor.png"> <td><img width="277px" src="imgs/ssh.png"></td>
</td> <td><img width="277px" src="imgs/docker.png"></td>
<td>
<img width="277px" src="imgs/ssh.png">
</td>
<td>
<img width="277px" src="imgs/docker.png">
</td>
</tr> </tr>
</table> </table>
@@ -67,9 +52,7 @@ Before you open an issue, please read the following:
2. Make sure whether the issue is caused by ServerBox app. 2. Make sure whether the issue is caused by ServerBox app.
3. Welcome all valid and positive feedback, subjective feedback (such as you think other UI is better) may not be accepted. 3. Welcome all valid and positive feedback, subjective feedback (such as you think other UI is better) may not be accepted.
After you read the above, you can: After you read the above, you can open an [issue](https://github.com/lollipopkit/flutter_server_box/issues/new).
- If you have **any question or feature request**, please open a [discussion](https://github.com/lollipopkit/flutter_server_box/discussions/new/choose).
- If ServerBox app has **any bug**, please open an [issue](https://github.com/lollipopkit/flutter_server_box/issues/new).
## 🧱 Contribution ## 🧱 Contribution
@@ -77,15 +60,8 @@ After you read the above, you can:
- [l10n guide](https://blog.lolli.tech/faq/) can be found in my blog. - [l10n guide](https://blog.lolli.tech/faq/) can be found in my blog.
## 👏🏼 Contributors
<a href="https://github.com/lollipopkit/flutter_server_box/graphs/contributors">
<img src="https://contrib.rocks/image?repo=lollipopkit/flutter_server_box" />
</a>
## 💡 My other apps ## 💡 My other apps
- [GPT Box](https://github.com/lollipopkit/flutter_gpt_box) - A third-party GPT Client for OpenAI API on all platforms. - [GPT Box](https://github.com/lollipopkit/flutter_gpt_box) - A third-party GPT Client for OpenAI API on all platforms.
- [2FA Box](https://github.com/lollipopkit/flutter_2fa) - Open source 2FA app for Android, iOS and the web.
- [More](https://github.com/lollipopkit) - Tools & etc. - [More](https://github.com/lollipopkit) - Tools & etc.

View File

@@ -22,7 +22,7 @@
## 🔖 特点 ## 🔖 特点
- 状态图表, `SSH` 终端, `SFTP`, `Docker & 包 & 进程` 管理器, 代码编辑器... - `状态图表`CPU、传感器、GPU 等), `SSH` 终端, `SFTP`, `Docker & 包 & 进程` 管理器...
- 特殊支持:`生物认证``推送``桌面小部件``watchOS App``跟随系统颜色`... - 特殊支持:`生物认证``推送``桌面小部件``watchOS App``跟随系统颜色`...
- 本地化 - 本地化
- English, 简体中文 - English, 简体中文
@@ -33,28 +33,16 @@
## 🏙️ 截屏 ## 🏙️ 截屏
<table> <table>
<tr> <tr>
<td> <td><img width="277px" src="imgs/server.png"></td>
<img width="277px" src="imgs/server.png"> <td><img width="277px" src="imgs/detail.png"></td>
</td> <td><img width="277px" src="imgs/sftp.png"></td>
<td>
<img width="277px" src="imgs/detail.png">
</td>
<td>
<img width="277px" src="imgs/sftp.png">
</td>
</tr> </tr>
</table> </table>
<table> <table>
<tr> <tr>
<td> <td><img width="277px" src="imgs/editor.png"> </td>
<img width="277px" src="imgs/editor.png"> <td><img width="277px" src="imgs/ssh.png"></td>
</td> <td><img width="277px" src="imgs/docker.png"></td>
<td>
<img width="277px" src="imgs/ssh.png">
</td>
<td>
<img width="277px" src="imgs/docker.png">
</td>
</tr> </tr>
</table> </table>
@@ -70,9 +58,7 @@
2. 反馈问题前请检查是否是 serverbox 的问题。 2. 反馈问题前请检查是否是 serverbox 的问题。
3. 欢迎所有有效、正面的反馈主观比如你觉得其他UI更好看的反馈不一定会接受 3. 欢迎所有有效、正面的反馈主观比如你觉得其他UI更好看的反馈不一定会接受
确认了解上述内容后 确认了解上述内容后,请在 [问题](https://github.com/lollipopkit/flutter_server_box/issues/new) 中反馈。
- 如果你有**任何问题或者功能请求**,请在 [讨论](https://github.com/lollipopkit/flutter_server_box/discussions/new/choose) 中交流。
- 如果 ServerBox app 有**任何 bug**,请在 [问题](https://github.com/lollipopkit/flutter_server_box/issues/new) 中反馈。
## 🧱 贡献 ## 🧱 贡献
@@ -80,15 +66,8 @@
- [本地化翻译指南](https://blog.lolli.tech/faq/) 可在我的博客中找到。 - [本地化翻译指南](https://blog.lolli.tech/faq/) 可在我的博客中找到。
## 👏🏼 贡献者
<a href="https://github.com/lollipopkit/flutter_server_box/graphs/contributors">
<img src="https://contrib.rocks/image?repo=lollipopkit/flutter_server_box" />
</a>
## 💡 我的其它 Apps ## 💡 我的其它 Apps
- [GPT Box](https://github.com/lollipopkit/flutter_gpt_box) - 支持 OpenAI API 的 第三方全平台客户端。 - [GPT Box](https://github.com/lollipopkit/flutter_gpt_box) - 支持 OpenAI API 的 第三方全平台客户端。
- [2FA Box](https://github.com/lollipopkit/flutter_2fa) - 开源的 2FA 应用。
- [更多](https://github.com/lollipopkit) - 工具 & etc. - [更多](https://github.com/lollipopkit) - 工具 & etc.

View File

@@ -260,9 +260,9 @@ class BackupPage extends StatelessWidget {
), ),
], ],
); );
} catch (e, trace) { } catch (e, s) {
Loggers.app.warning('Import backup failed', e, trace); Loggers.app.warning('Import backup failed', e, s);
context.showSnackBar(e.toString()); context.showErrDialog(e: e, s: s, operation: l10n.restore);
} }
} }
@@ -270,89 +270,52 @@ class BackupPage extends StatelessWidget {
webdavLoading.value = true; webdavLoading.value = true;
try { try {
final files = await Webdav.list(); final files = await Webdav.list();
if (files.isEmpty) { if (files.isEmpty) return context.showSnackBar(l10n.dirEmpty);
context.showSnackBar(l10n.dirEmpty);
webdavLoading.value = false;
return;
}
final fileName = await context.showRoundDialog<String>( final fileName = await context.showPickSingleDialog(
title: l10n.restore, title: l10n.restore,
child: SizedBox( items: files,
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),
); );
}, if (fileName == null) return;
),
),
actions: [
TextButton(
onPressed: () => context.pop(),
child: Text(l10n.cancel),
),
],
);
if (fileName == null) {
webdavLoading.value = false;
return;
}
final result = await Webdav.download(relativePath: fileName); final result = await Webdav.download(relativePath: fileName);
if (result != null) { if (result != null) {
Loggers.app.warning('Download webdav backup failed: $result'); throw result;
webdavLoading.value = false;
return;
} }
final dlFile = await File('${Paths.doc}/$fileName').readAsString(); final dlFile = await File('${Paths.doc}/$fileName').readAsString();
final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile); final dlBak = await Computer.shared.start(Backup.fromJsonString, dlFile);
await dlBak.restore(force: true); await dlBak.restore(force: true);
webdavLoading.value = false; } catch (e, s) {
} catch (e) { context.showErrDialog(e: e, s: s, operation: l10n.restore);
context.showSnackBar(e.toString()); Loggers.app.warning('Download webdav backup failed', e, s);
rethrow;
} finally { } finally {
webdavLoading.value = false; webdavLoading.value = false;
} }
} }
Future<void> _onTapWebdavUp(BuildContext context) async { Future<void> _onTapWebdavUp(BuildContext context) async {
try {
webdavLoading.value = true; webdavLoading.value = true;
final date = DateTime.now().ymdhms(ymdSep: "-", hmsSep: "-", sep: "-"); final date = DateTime.now().ymdhms(ymdSep: "-", hmsSep: "-", sep: "-");
final bakName = '$date-${Miscs.bakFileName}'; final bakName = '$date-${Miscs.bakFileName}';
try {
await Backup.backup(bakName); await Backup.backup(bakName);
final uploadResult = await Webdav.upload(relativePath: bakName); final uploadResult = await Webdav.upload(relativePath: bakName);
if (uploadResult != null) { if (uploadResult != null) {
Loggers.app.warning('Upload webdav backup failed: $uploadResult'); throw uploadResult;
context.showSnackBar(uploadResult.toString());
} else {
Loggers.app.info('Upload webdav backup success');
} }
} catch (e) { Loggers.app.info('Upload webdav backup success');
context.showSnackBar(e.toString()); } catch (e, s) {
rethrow; context.showErrDialog(e: e, s: s, operation: l10n.upload);
Loggers.app.warning('Upload webdav backup failed', e, s);
} finally { } finally {
webdavLoading.value = false; webdavLoading.value = false;
} }
} }
Future<void> _onTapWebdavSetting(BuildContext context) async { Future<void> _onTapWebdavSetting(BuildContext context) async {
final urlCtrl = TextEditingController( final url = TextEditingController(text: Stores.setting.webdavUrl.fetch());
text: Stores.setting.webdavUrl.fetch(), final user = TextEditingController(text: Stores.setting.webdavUser.fetch());
); final pwd = TextEditingController(text: Stores.setting.webdavPwd.fetch());
final userCtrl = TextEditingController(
text: Stores.setting.webdavUser.fetch(),
);
final pwdCtrl = TextEditingController(
text: Stores.setting.webdavPwd.fetch(),
);
final result = await context.showRoundDialog<bool>( final result = await context.showRoundDialog<bool>(
title: 'WebDAV', title: 'WebDAV',
child: Column( child: Column(
@@ -361,15 +324,15 @@ class BackupPage extends StatelessWidget {
Input( Input(
label: 'URL', label: 'URL',
hint: 'https://example.com/webdav/', hint: 'https://example.com/webdav/',
controller: urlCtrl, controller: url,
), ),
Input( Input(
label: l10n.user, label: l10n.user,
controller: userCtrl, controller: user,
), ),
Input( Input(
label: l10n.pwd, label: l10n.pwd,
controller: pwdCtrl, controller: pwd,
), ),
], ],
), ),
@@ -383,15 +346,13 @@ class BackupPage extends StatelessWidget {
], ],
); );
if (result == true) { if (result == true) {
final result = final result = await Webdav.test(url.text, user.text, pwd.text);
await Webdav.test(urlCtrl.text, userCtrl.text, pwdCtrl.text); if (result != null) {
if (result == null) {
context.showSnackBar(l10n.success);
} else {
context.showSnackBar(result); context.showSnackBar(result);
return; return;
} }
Webdav.changeClient(urlCtrl.text, userCtrl.text, pwdCtrl.text); context.showSnackBar(l10n.success);
Webdav.changeClient(url.text, user.text, pwd.text);
} }
} }
@@ -431,9 +392,9 @@ class BackupPage extends StatelessWidget {
), ),
], ],
); );
} catch (e, trace) { } catch (e, s) {
Loggers.app.warning('Import backup failed', e, trace); Loggers.app.warning('Import backup failed', e, s);
context.showSnackBar(e.toString()); context.showErrDialog(e: e, s: s, operation: l10n.restore);
} }
} }
@@ -468,11 +429,9 @@ class BackupPage extends StatelessWidget {
); );
context.showSnackBar(l10n.success); context.showSnackBar(l10n.success);
} }
} catch (e) { } catch (e, s) {
context.showRoundDialog( context.showErrDialog(e: e, s: s, operation: l10n.import);
title: l10n.error, Loggers.app.warning('Import servers failed', e, s);
child: Text(e.toString()),
);
} }
} }
} }