mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
opt.: backup
This commit is contained in:
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -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
|
||||||
|
|||||||
42
README.md
42
README.md
@@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
37
README_zh.md
37
README_zh.md
@@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => context.pop(),
|
|
||||||
child: Text(l10n.cancel),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
if (fileName == null) {
|
if (fileName == null) return;
|
||||||
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 {
|
||||||
|
webdavLoading.value = true;
|
||||||
|
final date = DateTime.now().ymdhms(ymdSep: "-", hmsSep: "-", sep: "-");
|
||||||
|
final bakName = '$date-${Miscs.bakFileName}';
|
||||||
try {
|
try {
|
||||||
webdavLoading.value = true;
|
|
||||||
final date = DateTime.now().ymdhms(ymdSep: "-", hmsSep: "-", sep: "-");
|
|
||||||
final bakName = '$date-${Miscs.bakFileName}';
|
|
||||||
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()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user