Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b56e033773 |
31
.github/workflows/release.yml
vendored
@@ -1,7 +1,6 @@
|
|||||||
name: Flutter Release
|
name: Flutter Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*"
|
- "v*"
|
||||||
@@ -19,12 +18,12 @@ jobs:
|
|||||||
- name: Install Flutter
|
- name: Install Flutter
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: "stable"
|
channel: 'stable'
|
||||||
flutter-version: "3.32.2"
|
flutter-version: '3.24.1'
|
||||||
- uses: actions/setup-java@v4
|
- uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: 'zulu'
|
||||||
java-version: "17"
|
java-version: '17'
|
||||||
- name: Fetch secrets
|
- name: Fetch secrets
|
||||||
run: |
|
run: |
|
||||||
curl -u ${{ secrets.BASIC_AUTH }} -o android/app/app.key ${{ secrets.URL_PREFIX }}app.key
|
curl -u ${{ secrets.BASIC_AUTH }} -o android/app/app.key ${{ secrets.URL_PREFIX }}app.key
|
||||||
@@ -54,28 +53,14 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Flutter
|
- name: Install Flutter
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
# Basic
|
|
||||||
sudo apt install -y clang cmake ninja-build pkg-config libgtk-3-dev libvulkan-dev desktop-file-utils wget
|
|
||||||
# App Specific
|
|
||||||
sudo apt install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libunwind-dev
|
|
||||||
# Packaging
|
|
||||||
sudo wget https://github.com/AppImage/appimagetool/releases/download/1.9.0/appimagetool-x86_64.AppImage -O /bin/appimagetool
|
|
||||||
sudo chmod +x /bin/appimagetool
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
dart run fl_build -p linux
|
dart run fl_build -p linux
|
||||||
- name: Rename artifacts
|
|
||||||
run: |
|
|
||||||
appimage_name=$(ls dist/*/*.AppImage)
|
|
||||||
mv $appimage_name ${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_amd64.appimage
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_amd64.appimage
|
${{ env.APP_NAME }}_${{ env.BUILD_NUMBER }}_amd64.AppImage
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
@@ -105,9 +90,9 @@ jobs:
|
|||||||
# uses: actions/checkout@v4
|
# uses: actions/checkout@v4
|
||||||
# - name: Install Flutter
|
# - name: Install Flutter
|
||||||
# uses: subosito/flutter-action@v2
|
# uses: subosito/flutter-action@v2
|
||||||
# with:
|
# with:
|
||||||
# channel: 'stable'
|
# channel: 'stable'
|
||||||
# flutter-version: '3.32.1'
|
# flutter-version: '3.22.2'
|
||||||
# - 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
|
||||||
|
|||||||
2
.gitignore
vendored
@@ -46,7 +46,6 @@ app.*.map.json
|
|||||||
/android/app/release
|
/android/app/release
|
||||||
|
|
||||||
/android/app/fjy.androidstudio.key
|
/android/app/fjy.androidstudio.key
|
||||||
/android/app/app.key
|
|
||||||
/release
|
/release
|
||||||
test.dart
|
test.dart
|
||||||
|
|
||||||
@@ -65,4 +64,3 @@ untranlated.json
|
|||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
more_build_data.json
|
more_build_data.json
|
||||||
trans.txt
|
trans.txt
|
||||||
android/app/.cxx
|
|
||||||
|
|||||||
31
README.md
@@ -6,17 +6,16 @@ English | [简体中文](README_zh.md)
|
|||||||
<a href="https://cdn.lpkt.cn/donate"><img alt="donate" src="https://img.shields.io/badge/donate-me-pink"></a>
|
<a href="https://cdn.lpkt.cn/donate"><img alt="donate" src="https://img.shields.io/badge/donate-me-pink"></a>
|
||||||
<img alt="lang" src="https://img.shields.io/badge/lang-dart-cyan">
|
<img alt="lang" src="https://img.shields.io/badge/lang-dart-cyan">
|
||||||
<img alt="license" src="https://img.shields.io/badge/license-GPLv3-yellow">
|
<img alt="license" src="https://img.shields.io/badge/license-GPLv3-yellow">
|
||||||
<a href="https://deepwiki.com/lollipopkit/flutter_server_box"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
A Flutter project which provide charts to display <a href="https://github.com/lollipopkit/flutter_server_box/issues/43">Linux</a> server status and tools to manage server.
|
A Flutter project which provide charts to display <a href="../../issues/43">Linux</a> server status and tools to manage server.
|
||||||
<br>
|
<br>
|
||||||
Especially thanks to <a href="https://github.com/TerminalStudio/dartssh2">dartssh2</a> & <a href="https://github.com/TerminalStudio/xterm.dart">xterm.dart</a>.
|
Especially thanks to <a href="https://github.com/TerminalStudio/dartssh2">dartssh2</a> & <a href="https://github.com/TerminalStudio/xterm.dart">xterm.dart</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## 🏙️ Screenshots
|
|
||||||
|
|
||||||
|
## 🏙️ Screenshots
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td><img width="200px" src="https://cdn.lpkt.cn/serverbox/screenshot/1.jpg"></td>
|
<td><img width="200px" src="https://cdn.lpkt.cn/serverbox/screenshot/1.jpg"></td>
|
||||||
@@ -26,26 +25,27 @@ Especially thanks to <a href="https://github.com/TerminalStudio/dartssh2">dartss
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
## 📥 Install
|
## 📥 Install
|
||||||
|
|
||||||
|Platform| From|
|
Platform | From
|
||||||
|--|--|
|
--- | ---
|
||||||
| iOS / macOS | [AppStore](https://apps.apple.com/app/id1586449703) |
|
iOS / macOS | [AppStore](https://apps.apple.com/app/id1586449703)
|
||||||
| Android | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) / [F-Droid](https://f-droid.org/packages/tech.lolli.toolbox) / [OpenAPK](https://www.openapk.net/serverbox/tech.lolli.toolbox/) |
|
Android | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lolli.tech/serverbox/?sort=time&order=desc&layout=grid) / [F-Droid](https://f-droid.org/packages/tech.lolli.toolbox) / [OpenAPK](https://www.openapk.net/serverbox/tech.lolli.toolbox/)
|
||||||
| Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) |
|
Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lolli.tech/serverbox/?sort=time&order=desc&layout=grid)
|
||||||
|
|
||||||
Please only download pkgs from the source that **you trust**!
|
Please only download pkgs from the source that **you trust**!
|
||||||
|
|
||||||
## 🔖 Feature
|
|
||||||
|
|
||||||
- `Status chart` (CPU, Sensors, GPU...), `SSH` Term, `SFTP`, `Docker & Process & Systemd`, `S.M.A.R.T`...
|
## 🔖 Feature
|
||||||
|
- `Status chart` (CPU, Sensors, GPU...), `SSH` Term, `SFTP`, `Docker & Process & Systemd`...
|
||||||
- Platform specific: `Bio auth`、`Msg push`、`Home widget`、`watchOS App`...
|
- Platform specific: `Bio auth`、`Msg push`、`Home widget`、`watchOS App`...
|
||||||
- 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), Türkçe [@mikropsoft](https://github.com/mikropsoft), Українська мова [@CakesTwix](https://github.com/CakesTwix); Español, Русский язык, Português, 日本語 (Generated by GPT)
|
- 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), Türkçe [@mikropsoft](https://github.com/mikropsoft), Українська мова [@CakesTwix](https://github.com/CakesTwix); Español, Русский язык, Português, 日本語 (Generated by GPT)
|
||||||
|
|
||||||
|
|
||||||
## 🆘 Help
|
## 🆘 Help
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://qm.qq.com/q/daCGa7eShG"><img alt="qq" src="https://img.shields.io/badge/QQ-Group-pink"></a>
|
|
||||||
<a href="https://t.me/lpktg"><img alt="donate" src="https://img.shields.io/badge/Telegram-lpktg-green"></a>
|
<a href="https://t.me/lpktg"><img alt="donate" src="https://img.shields.io/badge/Telegram-lpktg-green"></a>
|
||||||
<a href="https://discord.gg/SsVNbRhK7w"><img alt="discord" src="https://img.shields.io/badge/Discord-lpkt-purple"></a>
|
<a href="https://discord.gg/SsVNbRhK7w"><img alt="discord" src="https://img.shields.io/badge/Discord-lpkt-purple"></a>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,33 +54,30 @@ Please only download pkgs from the source that **you trust**!
|
|||||||
- **Common issues** can be found in [app wiki](https://github.com/lollipopkit/flutter_server_box/wiki).
|
- **Common issues** can be found in [app wiki](https://github.com/lollipopkit/flutter_server_box/wiki).
|
||||||
|
|
||||||
Before you open an issue, please read the following:
|
Before you open an issue, please read the following:
|
||||||
|
|
||||||
1. Paste the **entire log** (click the top right of the home page) in the issue template.
|
1. Paste the **entire log** (click the top right of the home page) in the issue template.
|
||||||
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 open an [issue](https://github.com/lollipopkit/flutter_server_box/issues/new).
|
After you read the above, you can open an [issue](https://github.com/lollipopkit/flutter_server_box/issues/new).
|
||||||
|
|
||||||
## 🧱 Contribution
|
|
||||||
|
|
||||||
|
## 🧱 Contribution
|
||||||
Any positive contribution is welcome.
|
Any positive contribution is welcome.
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
1. Setup [Flutter](https://flutter.dev/docs/get-started/install) environment.
|
1. Setup [Flutter](https://flutter.dev/docs/get-started/install) environment.
|
||||||
2. Clone this repo, run `flutter run` to start the app.
|
2. Clone this repo, run `flutter run` to start the app.
|
||||||
3. Run `dart run fl_build -p PLATFORM` to build the app.
|
3. Run `dart run fl_build -p PLATFORM` to build the app.
|
||||||
|
|
||||||
### Translation
|
### Translation
|
||||||
|
|
||||||
- [Guide](https://blog.lpkt.cn/posts/faq/) can be found in my blog.
|
- [Guide](https://blog.lpkt.cn/posts/faq/) can be found in my blog.
|
||||||
- We need your help! Just feel free to open a PR.
|
- We need your help! Just feel free to open a PR.
|
||||||
|
|
||||||
## 💡 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.
|
||||||
- [More](https://github.com/lollipopkit) - Tools & etc.
|
- [More](https://github.com/lollipopkit) - Tools & etc.
|
||||||
|
|
||||||
## 📝 License
|
|
||||||
|
|
||||||
|
## 📝 License
|
||||||
`GPL v3 lollipopkit`
|
`GPL v3 lollipopkit`
|
||||||
|
|||||||
32
README_zh.md
@@ -6,17 +6,16 @@
|
|||||||
<a href="https://cdn.lpkt.cn/donate"><img alt="donate" src="https://img.shields.io/badge/捐赠-我-pink"></a>
|
<a href="https://cdn.lpkt.cn/donate"><img alt="donate" src="https://img.shields.io/badge/捐赠-我-pink"></a>
|
||||||
<img alt="语言" src="https://img.shields.io/badge/语言-dart-cyan">
|
<img alt="语言" src="https://img.shields.io/badge/语言-dart-cyan">
|
||||||
<img alt="license" src="https://img.shields.io/badge/证书-GPLv3-yellow">
|
<img alt="license" src="https://img.shields.io/badge/证书-GPLv3-yellow">
|
||||||
<a href="https://deepwiki.com/lollipopkit/flutter_server_box"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
使用 Flutter 开发的 <a href="https://github.com/lollipopkit/flutter_server_box/issues/43">Linux</a> 服务器工具箱,提供服务器状态图表和管理工具。
|
使用 Flutter 开发的 <a href="../../issues/43">Linux</a> 服务器工具箱,提供服务器状态图表和管理工具。
|
||||||
<br>
|
<br>
|
||||||
特别感谢 <a href="https://github.com/TerminalStudio/dartssh2">dartssh2</a> & <a href="https://github.com/TerminalStudio/xterm.dart">xterm.dart</a>。
|
特别感谢 <a href="https://github.com/TerminalStudio/dartssh2">dartssh2</a> & <a href="https://github.com/TerminalStudio/xterm.dart">xterm.dart</a>。
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## 🏙️ 截屏
|
|
||||||
|
|
||||||
|
## 🏙️ 截屏
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td><img width="200px" src="https://cdn.lpkt.cn/serverbox/screenshot/1.jpg"></td>
|
<td><img width="200px" src="https://cdn.lpkt.cn/serverbox/screenshot/1.jpg"></td>
|
||||||
@@ -26,19 +25,20 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
## 📥 安装
|
## 📥 安装
|
||||||
|
|
||||||
平台|下载
|
平台 | 下载
|
||||||
--|--
|
--- | ---
|
||||||
iOS / macOS | [AppStore](https://apps.apple.com/app/id1586449703)
|
iOS / macOS | [AppStore](https://apps.apple.com/app/id1586449703)
|
||||||
Android | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) / [F-Droid](https://f-droid.org/packages/tech.lolli.toolbox) / [OpenAPK](https://www.openapk.net/serverbox/tech.lolli.toolbox/)
|
Android | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lolli.tech/serverbox/?sort=time&order=desc&layout=grid) / [F-Droid](https://f-droid.org/packages/tech.lolli.toolbox) / [OpenAPK](https://www.openapk.net/serverbox/tech.lolli.toolbox/)
|
||||||
Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid)
|
Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lolli.tech/serverbox/?sort=time&order=desc&layout=grid)
|
||||||
|
|
||||||
请从 **信任** 的来源下载!
|
请从 **信任** 的来源下载!
|
||||||
|
|
||||||
## 🔖 特点
|
|
||||||
|
|
||||||
- `状态图表`(CPU、传感器、GPU 等), `SSH` 终端, `SFTP`, `Docker & 进程 & Systemd` 管理,`S.M.A.R.T`...
|
## 🔖 特点
|
||||||
|
- `状态图表`(CPU、传感器、GPU 等), `SSH` 终端, `SFTP`, `Docker & 进程 & Systemd` 管理...
|
||||||
- 特殊支持:`生物认证`、`推送`、`桌面小部件`、`watchOS App`、`跟随系统颜色`...
|
- 特殊支持:`生物认证`、`推送`、`桌面小部件`、`watchOS App`、`跟随系统颜色`...
|
||||||
- 本地化
|
- 本地化
|
||||||
- English, 简体中文
|
- English, 简体中文
|
||||||
@@ -46,10 +46,10 @@ Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/rel
|
|||||||
- 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), Türkçe [@mikropsoft](https://github.com/mikropsoft), Українська мова [@CakesTwix](https://github.com/CakesTwix);
|
- 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), Türkçe [@mikropsoft](https://github.com/mikropsoft), Українська мова [@CakesTwix](https://github.com/CakesTwix);
|
||||||
- 感谢贡献者们!
|
- 感谢贡献者们!
|
||||||
|
|
||||||
|
|
||||||
## 🆘 帮助
|
## 🆘 帮助
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://qm.qq.com/q/daCGa7eShG"><img alt="qq" src="https://img.shields.io/badge/QQ-群-pink"></a>
|
|
||||||
<a href="https://t.me/lpktg"><img alt="donate" src="https://img.shields.io/badge/Telegram-lpktg-green"></a>
|
<a href="https://t.me/lpktg"><img alt="donate" src="https://img.shields.io/badge/Telegram-lpktg-green"></a>
|
||||||
<a href="https://discord.gg/SsVNbRhK7w"><img alt="discord" src="https://img.shields.io/badge/Discord-lpkt-purple"></a>
|
<a href="https://discord.gg/SsVNbRhK7w"><img alt="discord" src="https://img.shields.io/badge/Discord-lpkt-purple"></a>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,30 +58,26 @@ Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/rel
|
|||||||
- **常见问题** 可以在 [app wiki](https://github.com/lollipopkit/flutter_server_box/wiki/主页) 查看。
|
- **常见问题** 可以在 [app wiki](https://github.com/lollipopkit/flutter_server_box/wiki/主页) 查看。
|
||||||
|
|
||||||
反馈前须知:
|
反馈前须知:
|
||||||
|
|
||||||
1. 反馈问题请附带 log(点击首页右上角),并以 bug 模版提交。
|
1. 反馈问题请附带 log(点击首页右上角),并以 bug 模版提交。
|
||||||
2. 反馈问题前请检查是否是 serverbox 的问题。
|
2. 反馈问题前请检查是否是 serverbox 的问题。
|
||||||
3. 欢迎所有有效、正面的反馈,主观(比如你觉得其他UI更好看)的反馈不一定会接受
|
3. 欢迎所有有效、正面的反馈,主观(比如你觉得其他UI更好看)的反馈不一定会接受
|
||||||
|
|
||||||
## 🧱 贡献
|
|
||||||
|
|
||||||
|
## 🧱 贡献
|
||||||
任何正面的贡献都欢迎。
|
任何正面的贡献都欢迎。
|
||||||
|
|
||||||
### 开发
|
### 开发
|
||||||
|
|
||||||
1. 安装 [Flutter](https://flutter.dev/docs/get-started/install)
|
1. 安装 [Flutter](https://flutter.dev/docs/get-started/install)
|
||||||
2. 克隆这个仓库, 运行 `flutter run` 启动应用
|
2. 克隆这个仓库, 运行 `flutter run` 启动应用
|
||||||
3. 运行 `dart run fl_build -p PLATFORM` 构建应用
|
3. 运行 `dart run fl_build -p PLATFORM` 构建应用
|
||||||
|
|
||||||
### 翻译
|
### 翻译
|
||||||
|
[指南](https://blog.lolli.tech/faq/) 可在我的博客中找到。
|
||||||
[指南](https://blog.lpkt.cn/faq/) 可在我的博客中找到。
|
|
||||||
|
|
||||||
## 💡 我的其它 Apps
|
## 💡 我的其它 Apps
|
||||||
|
|
||||||
- [GPT Box](https://github.com/lollipopkit/flutter_gpt_box) - 支持 OpenAI API 的 第三方全平台客户端。
|
- [GPT Box](https://github.com/lollipopkit/flutter_gpt_box) - 支持 OpenAI API 的 第三方全平台客户端。
|
||||||
- [更多](https://github.com/lollipopkit) - 工具 & etc.
|
- [更多](https://github.com/lollipopkit) - 工具 & etc.
|
||||||
|
|
||||||
## 📝 协议
|
|
||||||
|
|
||||||
|
## 📝 协议
|
||||||
`GPL v3 lollipopkit`
|
`GPL v3 lollipopkit`
|
||||||
|
|||||||
@@ -11,13 +11,11 @@ include: package:flutter_lints/flutter.yaml
|
|||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
exclude:
|
exclude:
|
||||||
- "**/*.g.dart"
|
- '**/*.g.dart'
|
||||||
language:
|
language:
|
||||||
# strict-casts: true
|
# strict-casts: true
|
||||||
# strict-inference: true
|
# strict-inference: true
|
||||||
# strict-raw-types: true
|
# strict-raw-types: true
|
||||||
errors:
|
|
||||||
invalid_annotation_target: ignore
|
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
# The lint rules applied to this project can be customized in the
|
# The lint rules applied to this project can be customized in the
|
||||||
@@ -43,9 +41,8 @@ linter:
|
|||||||
annotate_overrides: true
|
annotate_overrides: true
|
||||||
avoid_empty_else: true
|
avoid_empty_else: true
|
||||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
avoid_return_types_on_setters: true
|
avoid_return_types_on_setters: true
|
||||||
directives_ordering: true # Enable sorting of imports
|
|
||||||
|
|
||||||
# Additional information about this file can be found at
|
# Additional information about this file can be found at
|
||||||
# https://dart.dev/guides/language/analysis-options
|
# https://dart.dev/guides/language/analysis-options
|
||||||
|
|||||||
@@ -85,11 +85,11 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug {
|
debug {
|
||||||
// No applicationIdSuffix or resValue here
|
applicationIdSuffix '.debug'
|
||||||
}
|
}
|
||||||
|
|
||||||
profile {
|
profile {
|
||||||
// No applicationIdSuffix or resValue here
|
applicationIdSuffix '.debug'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="@string/app_name"
|
android:label="ServerBox"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|layoutDirection|fontScale|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
|
|||||||
@@ -4,158 +4,85 @@ import android.app.*
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.util.Log
|
|
||||||
import java.io.File
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class ForegroundService : Service() {
|
class ForegroundService : Service() {
|
||||||
private val chanId = "ForegroundServiceChannel"
|
private val chanId = "ForegroundServiceChannel"
|
||||||
|
|
||||||
private fun logError(message: String, error: Throwable? = null) {
|
|
||||||
Log.e("ForegroundService", message, error)
|
|
||||||
try {
|
|
||||||
val logFile = File(getExternalFilesDir(null), "server_box.log")
|
|
||||||
val timestamp = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(Date())
|
|
||||||
val logMessage = "$timestamp [ForegroundService] ERROR: $message\n${error?.stackTraceToString() ?: ""}\n"
|
|
||||||
logFile.appendText(logMessage)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("ForegroundService", "Failed to write log", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
Log.d("ForegroundService", "Service onCreate")
|
|
||||||
createNotificationChannel()
|
createNotificationChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
try {
|
when (intent?.action) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
"ACTION_STOP_FOREGROUND" -> {
|
||||||
androidx.core.content.ContextCompat.checkSelfPermission(
|
|
||||||
this, android.Manifest.permission.POST_NOTIFICATIONS
|
|
||||||
) != android.content.pm.PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
Log.w("ForegroundService", "Notification permission denied. Stopping service.")
|
|
||||||
stopForegroundService()
|
stopForegroundService()
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
else -> {
|
||||||
if (intent == null) {
|
val notification = createNotification()
|
||||||
Log.w("ForegroundService", "onStartCommand called with null intent")
|
|
||||||
stopForegroundService()
|
|
||||||
return START_NOT_STICKY
|
|
||||||
}
|
|
||||||
|
|
||||||
val action = intent.action
|
|
||||||
Log.d("ForegroundService", "onStartCommand action=$action")
|
|
||||||
|
|
||||||
// Create notification before starting foreground
|
|
||||||
val notification = createNotification()
|
|
||||||
|
|
||||||
// Use try-catch for startForeground
|
|
||||||
try {
|
|
||||||
startForeground(1, notification)
|
startForeground(1, notification)
|
||||||
} catch (e: Exception) {
|
return START_STICKY
|
||||||
logError("Failed to start foreground", e)
|
|
||||||
stopSelf()
|
|
||||||
return START_NOT_STICKY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (action) {
|
|
||||||
"ACTION_STOP_FOREGROUND" -> {
|
|
||||||
stopForegroundService()
|
|
||||||
START_NOT_STICKY
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
START_STICKY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError("Error in onStartCommand", e)
|
|
||||||
stopSelf()
|
|
||||||
return START_NOT_STICKY
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? {
|
override fun onBind(intent: Intent): IBinder? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val manager = getSystemService(NotificationManager::class.java)
|
|
||||||
if (manager == null) {
|
|
||||||
Log.e("ForegroundService", "Failed to get NotificationManager")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val serviceChannel = NotificationChannel(
|
val serviceChannel = NotificationChannel(
|
||||||
chanId,
|
chanId,
|
||||||
"ForegroundServiceChannel",
|
chanId,
|
||||||
NotificationManager.IMPORTANCE_DEFAULT
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
).apply {
|
)
|
||||||
description = "For foreground service"
|
val manager = getSystemService(NotificationManager::class.java)
|
||||||
}
|
|
||||||
manager.createNotificationChannel(serviceChannel)
|
manager.createNotificationChannel(serviceChannel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotification(): Notification {
|
private fun createNotification(): Notification {
|
||||||
try {
|
val notificationIntent = Intent(this, MainActivity::class.java)
|
||||||
val notificationIntent = Intent(this, MainActivity::class.java)
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
this,
|
||||||
this,
|
0,
|
||||||
0,
|
notificationIntent,
|
||||||
notificationIntent,
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
)
|
||||||
)
|
|
||||||
|
|
||||||
val deleteIntent = Intent(this, ForegroundService::class.java).apply {
|
val deleteIntent = Intent(this, ForegroundService::class.java).apply {
|
||||||
action = "ACTION_STOP_FOREGROUND"
|
action = "ACTION_STOP_FOREGROUND"
|
||||||
}
|
}
|
||||||
val deletePendingIntent = PendingIntent.getService(
|
val deletePendingIntent = PendingIntent.getService(
|
||||||
this,
|
this,
|
||||||
0,
|
0,
|
||||||
deleteIntent,
|
deleteIntent,
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
|
||||||
val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
Notification.Builder(this, chanId)
|
Notification.Builder(this, chanId)
|
||||||
} else {
|
|
||||||
Notification.Builder(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder
|
|
||||||
.setContentTitle("Server Box")
|
.setContentTitle("Server Box")
|
||||||
.setContentText("Running in background")
|
.setContentText("Open the app")
|
||||||
.setSmallIcon(R.mipmap.ic_launcher)
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.addAction(android.R.drawable.ic_delete, "Stop", deletePendingIntent)
|
.addAction(android.R.drawable.ic_delete, "Stop", deletePendingIntent)
|
||||||
.build()
|
.build()
|
||||||
} catch (e: Exception) {
|
} else {
|
||||||
logError("Error creating notification", e)
|
Notification.Builder(this)
|
||||||
// Return a basic notification as fallback
|
|
||||||
return Notification.Builder(this)
|
|
||||||
.setContentTitle("Server Box")
|
.setContentTitle("Server Box")
|
||||||
|
.setContentText("Open the app")
|
||||||
.setSmallIcon(R.mipmap.ic_launcher)
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.addAction(android.R.drawable.ic_delete, "Stop", deletePendingIntent)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stopForegroundService() {
|
fun stopForegroundService() {
|
||||||
try {
|
stopForeground(true)
|
||||||
stopForeground(true)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError("Error stopping foreground", e)
|
|
||||||
}
|
|
||||||
stopSelf()
|
stopSelf()
|
||||||
Log.d("ForegroundService", "ForegroundService stopped")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
Log.d("ForegroundService", "Service onDestroy")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,15 +9,13 @@ import androidx.core.content.ContextCompat
|
|||||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import tech.lolli.toolbox.widget.HomeWidget
|
|
||||||
|
|
||||||
class MainActivity: FlutterFragmentActivity() {
|
class MainActivity: FlutterFragmentActivity() {
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
val binaryMessenger = flutterEngine.dartExecutor.binaryMessenger
|
val binaryMessenger = flutterEngine.dartExecutor.binaryMessenger
|
||||||
|
|
||||||
MethodChannel(binaryMessenger, "tech.lolli.toolbox/main_chan").apply {
|
MethodChannel(binaryMessenger, "tech.lolli.toolbox/app_retain").apply {
|
||||||
setMethodCallHandler { method, result ->
|
setMethodCallHandler { method, result ->
|
||||||
when (method.method) {
|
when (method.method) {
|
||||||
"sendToBackground" -> {
|
"sendToBackground" -> {
|
||||||
@@ -25,19 +23,12 @@ class MainActivity: FlutterFragmentActivity() {
|
|||||||
result.success(null)
|
result.success(null)
|
||||||
}
|
}
|
||||||
"startService" -> {
|
"startService" -> {
|
||||||
try {
|
reqPerm()
|
||||||
reqPerm()
|
val serviceIntent = Intent(this@MainActivity, ForegroundService::class.java)
|
||||||
val serviceIntent = Intent(this@MainActivity, ForegroundService::class.java)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
startForegroundService(serviceIntent)
|
||||||
startForegroundService(serviceIntent)
|
} else {
|
||||||
} else {
|
startService(serviceIntent)
|
||||||
startService(serviceIntent)
|
|
||||||
}
|
|
||||||
result.success(null)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Log error but don't crash
|
|
||||||
android.util.Log.e("MainActivity", "Failed to start service: ${e.message}")
|
|
||||||
result.error("SERVICE_ERROR", e.message, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"stopService" -> {
|
"stopService" -> {
|
||||||
@@ -45,12 +36,6 @@ class MainActivity: FlutterFragmentActivity() {
|
|||||||
stopService(serviceIntent)
|
stopService(serviceIntent)
|
||||||
result.success(null)
|
result.success(null)
|
||||||
}
|
}
|
||||||
"updateHomeWidget" -> {
|
|
||||||
val intent = Intent(this@MainActivity, HomeWidget::class.java)
|
|
||||||
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
|
||||||
sendBroadcast(intent)
|
|
||||||
result.success(null)
|
|
||||||
}
|
|
||||||
else -> {
|
else -> {
|
||||||
result.notImplemented()
|
result.notImplemented()
|
||||||
}
|
}
|
||||||
@@ -61,21 +46,13 @@ class MainActivity: FlutterFragmentActivity() {
|
|||||||
|
|
||||||
private fun reqPerm() {
|
private fun reqPerm() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
|
||||||
|
|
||||||
// Check if we already have the permission to avoid unnecessary prompts
|
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
try {
|
ActivityCompat.requestPermissions(
|
||||||
ActivityCompat.requestPermissions(
|
this,
|
||||||
this,
|
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
||||||
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
123,
|
||||||
123,
|
)
|
||||||
)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Log error but don't crash
|
|
||||||
android.util.Log.e("MainActivity", "Failed to request permissions: ${e.message}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,15 @@ import android.appwidget.AppWidgetProvider
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import tech.lolli.toolbox.R
|
import tech.lolli.toolbox.R
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.net.HttpURLConnection
|
|
||||||
import java.io.FileNotFoundException
|
|
||||||
|
|
||||||
class HomeWidget : AppWidgetProvider() {
|
class HomeWidget : AppWidgetProvider() {
|
||||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||||
@@ -26,6 +23,7 @@ class HomeWidget : AppWidgetProvider() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
|
private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
|
||||||
val views = RemoteViews(context.packageName, R.layout.home_widget)
|
val views = RemoteViews(context.packageName, R.layout.home_widget)
|
||||||
val sp = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
|
val sp = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
|
||||||
@@ -38,10 +36,6 @@ class HomeWidget : AppWidgetProvider() {
|
|||||||
url = gUrl
|
url = gUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.isNullOrEmpty()) {
|
|
||||||
Log.e("HomeWidget", "URL not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
val intentUpdate = Intent(context, HomeWidget::class.java)
|
val intentUpdate = Intent(context, HomeWidget::class.java)
|
||||||
intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
val ids = intArrayOf(appWidgetId)
|
val ids = intArrayOf(appWidgetId)
|
||||||
@@ -60,13 +54,11 @@ class HomeWidget : AppWidgetProvider() {
|
|||||||
views.setOnClickPendingIntent(R.id.widget_container, pendingUpdate)
|
views.setOnClickPendingIntent(R.id.widget_container, pendingUpdate)
|
||||||
|
|
||||||
if (url.isNullOrEmpty()) {
|
if (url.isNullOrEmpty()) {
|
||||||
views.setTextViewText(R.id.widget_name, "No URL")
|
views.setViewVisibility(R.id.widget_cpu_label, View.INVISIBLE)
|
||||||
// Update the widget to display a message for missing URL
|
views.setViewVisibility(R.id.widget_mem_label, View.INVISIBLE)
|
||||||
views.setViewVisibility(R.id.error_message, View.VISIBLE)
|
views.setViewVisibility(R.id.widget_disk_label, View.INVISIBLE)
|
||||||
views.setTextViewText(R.id.error_message, "Please configure the widget URL.")
|
views.setViewVisibility(R.id.widget_net_label, View.INVISIBLE)
|
||||||
views.setViewVisibility(R.id.widget_content, View.GONE)
|
views.setTextViewText(R.id.widget_name, "ID: $appWidgetId")
|
||||||
views.setFloat(R.id.widget_name, "setAlpha", 1f)
|
|
||||||
views.setFloat(R.id.error_message, "setAlpha", 1f)
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -76,53 +68,44 @@ class HomeWidget : AppWidgetProvider() {
|
|||||||
views.setViewVisibility(R.id.widget_net_label, View.VISIBLE)
|
views.setViewVisibility(R.id.widget_net_label, View.VISIBLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val connection = URL(url).openConnection() as HttpURLConnection
|
val jsonStr = URL(url).readText()
|
||||||
connection.requestMethod = "GET"
|
val jsonObject = JSONObject(jsonStr)
|
||||||
val responseCode = connection.responseCode
|
val data = jsonObject.getJSONObject("data")
|
||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
val server = data.getString("name")
|
||||||
val jsonStr = connection.inputStream.bufferedReader().use { it.readText() }
|
val cpu = data.getString("cpu")
|
||||||
val jsonObject = JSONObject(jsonStr)
|
val mem = data.getString("mem")
|
||||||
val data = jsonObject.getJSONObject("data")
|
val disk = data.getString("disk")
|
||||||
val server = data.getString("name")
|
val net = data.getString("net")
|
||||||
val cpu = data.getString("cpu")
|
|
||||||
val mem = data.getString("mem")
|
GlobalScope.launch(Dispatchers.Main) main@ {
|
||||||
val disk = data.getString("disk")
|
// mem or disk is empty -> get status failed
|
||||||
val net = data.getString("net")
|
// (cpu | net) isEmpty -> data is not ready
|
||||||
withContext(Dispatchers.Main) {
|
if (mem.isEmpty() || disk.isEmpty()) {
|
||||||
if (mem.isEmpty() || disk.isEmpty()) {
|
return@main
|
||||||
Log.e("HomeWidget", "Failed to retrieve status: Memory or disk information is empty")
|
|
||||||
return@withContext
|
|
||||||
}
|
|
||||||
views.setTextViewText(R.id.widget_name, server)
|
|
||||||
views.setTextViewText(R.id.widget_cpu, cpu)
|
|
||||||
views.setTextViewText(R.id.widget_mem, mem)
|
|
||||||
views.setTextViewText(R.id.widget_disk, disk)
|
|
||||||
views.setTextViewText(R.id.widget_net, net)
|
|
||||||
val timeStr = android.text.format.DateFormat.format("HH:mm", java.util.Date()).toString()
|
|
||||||
views.setTextViewText(R.id.widget_time, timeStr)
|
|
||||||
views.setFloat(R.id.widget_name, "setAlpha", 1f)
|
|
||||||
views.setFloat(R.id.widget_cpu_label, "setAlpha", 1f)
|
|
||||||
views.setFloat(R.id.widget_mem_label, "setAlpha", 1f)
|
|
||||||
views.setFloat(R.id.widget_disk_label, "setAlpha", 1f)
|
|
||||||
views.setFloat(R.id.widget_net_label, "setAlpha", 1f)
|
|
||||||
views.setFloat(R.id.widget_time, "setAlpha", 1f)
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
|
||||||
}
|
}
|
||||||
} else {
|
views.setTextViewText(R.id.widget_name, server)
|
||||||
throw FileNotFoundException("HTTP response code: $responseCode")
|
|
||||||
|
views.setTextViewText(R.id.widget_cpu, cpu)
|
||||||
|
views.setTextViewText(R.id.widget_mem, mem)
|
||||||
|
views.setTextViewText(R.id.widget_disk, disk)
|
||||||
|
views.setTextViewText(R.id.widget_net, net)
|
||||||
|
|
||||||
|
val timeStr = android.text.format.DateFormat.format("HH:mm", java.util.Date()).toString()
|
||||||
|
views.setTextViewText(R.id.widget_time, timeStr)
|
||||||
|
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("HomeWidget", "Error updating widget: ${e.localizedMessage}", e)
|
println("ServerBoxHomeWidget: ${e.localizedMessage}")
|
||||||
withContext(Dispatchers.Main) {
|
GlobalScope.launch(Dispatchers.Main) main@ {
|
||||||
views.setTextViewText(R.id.widget_name, "Error")
|
views.setViewVisibility(R.id.widget_cpu_label, View.INVISIBLE)
|
||||||
// Update the widget to display a message for data retrieval failure
|
views.setViewVisibility(R.id.widget_mem_label, View.INVISIBLE)
|
||||||
views.setViewVisibility(R.id.error_message, View.VISIBLE)
|
views.setViewVisibility(R.id.widget_disk_label, View.INVISIBLE)
|
||||||
views.setTextViewText(R.id.error_message, "Failed to retrieve data.")
|
views.setViewVisibility(R.id.widget_net_label, View.INVISIBLE)
|
||||||
views.setViewVisibility(R.id.widget_content, View.GONE)
|
views.setTextViewText(R.id.widget_name, "ID: $appWidgetId")
|
||||||
views.setFloat(R.id.widget_name, "setAlpha", 1f)
|
views.setTextViewText(R.id.widget_mem, e.localizedMessage)
|
||||||
views.setFloat(R.id.error_message, "setAlpha", 1f)
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,151 +16,124 @@
|
|||||||
android:textSize="23sp"
|
android:textSize="23sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:alpha="0"
|
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
tools:text="Server Name" />
|
tools:text="Server Name" />
|
||||||
|
|
||||||
<!-- Wrap the content in a LinearLayout for easy visibility management -->
|
<RelativeLayout
|
||||||
<LinearLayout
|
android:id="@+id/widget_container_inner"
|
||||||
android:id="@+id/widget_content"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:gravity="center_vertical"
|
||||||
android:layout_below="@id/widget_name"
|
|
||||||
android:paddingTop="13dp">
|
android:paddingTop="13dp">
|
||||||
|
|
||||||
<RelativeLayout
|
<LinearLayout
|
||||||
android:id="@+id/widget_container_inner"
|
android:id="@+id/widget_cpu_label"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="2.7dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:paddingTop="13dp"
|
android:orientation="horizontal">
|
||||||
android:animateLayoutChanges="true">
|
|
||||||
|
|
||||||
<LinearLayout
|
<ImageView
|
||||||
android:id="@+id/widget_cpu_label"
|
android:layout_width="17dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="17dp"
|
||||||
|
android:src="@drawable/speed_24">
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_cpu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="2.7dp"
|
android:layout_marginStart="11dp"
|
||||||
android:gravity="center_vertical"
|
android:singleLine="true"
|
||||||
android:orientation="horizontal">
|
android:ellipsize = "marquee"
|
||||||
|
android:textColor="@color/widgetSummaryText"
|
||||||
<ImageView
|
android:textSize="12.7sp"
|
||||||
android:layout_width="17dp"
|
tools:text="CPU" />
|
||||||
android:layout_height="17dp"
|
|
||||||
android:src="@drawable/speed_24">
|
|
||||||
</ImageView>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/widget_cpu"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="11dp"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize = "marquee"
|
|
||||||
android:textColor="@color/widgetSummaryText"
|
|
||||||
android:textSize="12.7sp"
|
|
||||||
tools:text="CPU" />
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/widget_mem_label"
|
android:id="@+id/widget_mem_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="2.7dp"
|
||||||
|
android:layout_below="@id/widget_cpu_label"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="17dp"
|
||||||
|
android:layout_height="17dp"
|
||||||
|
android:src="@drawable/memory_24">
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_mem"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="2.7dp"
|
android:layout_marginStart="11dp"
|
||||||
android:layout_below="@id/widget_cpu_label"
|
android:maxLines="1"
|
||||||
android:gravity="center_vertical"
|
android:textColor="@color/widgetSummaryText"
|
||||||
android:orientation="horizontal">
|
android:textSize="12.7sp"
|
||||||
|
tools:text="Mem" />
|
||||||
|
|
||||||
<ImageView
|
</LinearLayout>
|
||||||
android:layout_width="17dp"
|
|
||||||
android:layout_height="17dp"
|
|
||||||
android:src="@drawable/memory_24">
|
|
||||||
</ImageView>
|
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/widget_mem"
|
android:id="@+id/widget_disk_label"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="11dp"
|
android:paddingBottom="2.7dp"
|
||||||
android:maxLines="1"
|
android:layout_below="@id/widget_mem_label"
|
||||||
android:textColor="@color/widgetSummaryText"
|
android:gravity="center_vertical"
|
||||||
android:textSize="12.7sp"
|
android:orientation="horizontal">
|
||||||
tools:text="Mem" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
<ImageView
|
||||||
|
android:layout_width="17dp"
|
||||||
|
android:layout_height="17dp"
|
||||||
|
android:src="@drawable/storage_24">
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:id="@+id/widget_disk_label"
|
android:id="@+id/widget_disk"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="2.7dp"
|
android:layout_marginStart="11dp"
|
||||||
android:layout_below="@id/widget_mem_label"
|
android:maxLines="1"
|
||||||
android:gravity="center_vertical"
|
android:textColor="@color/widgetSummaryText"
|
||||||
android:orientation="horizontal">
|
android:textSize="12.7sp"
|
||||||
|
tools:text="Disk" />
|
||||||
|
|
||||||
<ImageView
|
</LinearLayout>
|
||||||
android:layout_width="17dp"
|
|
||||||
android:layout_height="17dp"
|
|
||||||
android:src="@drawable/storage_24">
|
|
||||||
</ImageView>
|
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/widget_disk"
|
android:id="@+id/widget_net_label"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="11dp"
|
android:layout_below="@id/widget_disk_label"
|
||||||
android:maxLines="1"
|
android:gravity="center_vertical"
|
||||||
android:textColor="@color/widgetSummaryText"
|
android:orientation="horizontal">
|
||||||
android:textSize="12.7sp"
|
|
||||||
tools:text="Disk" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
<ImageView
|
||||||
|
android:layout_width="17dp"
|
||||||
|
android:layout_height="17dp"
|
||||||
|
android:src="@drawable/net_24">
|
||||||
|
</ImageView>
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:id="@+id/widget_net_label"
|
android:id="@+id/widget_net"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/widget_disk_label"
|
android:layout_marginStart="11dp"
|
||||||
android:gravity="center_vertical"
|
android:maxLines="1"
|
||||||
android:orientation="horizontal">
|
android:textColor="@color/widgetSummaryText"
|
||||||
|
android:textSize="12.7sp"
|
||||||
|
tools:text="Net" />
|
||||||
|
|
||||||
<ImageView
|
</LinearLayout>
|
||||||
android:layout_width="17dp"
|
|
||||||
android:layout_height="17dp"
|
|
||||||
android:src="@drawable/net_24">
|
|
||||||
</ImageView>
|
|
||||||
|
|
||||||
<TextView
|
</RelativeLayout>
|
||||||
android:id="@+id/widget_net"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="11dp"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="@color/widgetSummaryText"
|
|
||||||
android:textSize="12.7sp"
|
|
||||||
tools:text="Net" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- Add a TextView for error messages -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/error_message"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/widget_name"
|
|
||||||
android:textColor="@color/widgetSummaryText"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:alpha="0"
|
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
tools:text="Error message" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/widget_time"
|
android:id="@+id/widget_time"
|
||||||
@@ -170,8 +143,6 @@
|
|||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:textColor="@color/widgetSummaryText"
|
android:textColor="@color/widgetSummaryText"
|
||||||
android:textSize="11sp"
|
android:textSize="11sp"
|
||||||
android:alpha="0"
|
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
tools:text="UpdateTime" />
|
tools:text="UpdateTime" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
Before Width: | Height: | Size: 761 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 895 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="app_name">ServerBox</string>
|
|
||||||
</resources>
|
|
||||||
@@ -9,23 +9,6 @@ rootProject.buildDir = '../build'
|
|||||||
subprojects {
|
subprojects {
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects { subproject ->
|
|
||||||
// Only works on com.android.application(the main app module)
|
|
||||||
if (subproject.plugins.hasPlugin('com.android.application')) {
|
|
||||||
subproject.afterEvaluate {
|
|
||||||
android.buildTypes.matching { it.name == 'profile' }.all { buildType ->
|
|
||||||
buildType.applicationIdSuffix = ".profile"
|
|
||||||
buildTypes.profile.resValue 'string', 'app_name', 'SrvBxP'
|
|
||||||
}
|
|
||||||
android.buildTypes.matching { it.name == 'debug' }.all { buildType ->
|
|
||||||
buildType.applicationIdSuffix = ".debug"
|
|
||||||
buildTypes.debug.resValue 'string', 'app_name', 'SrvBxD'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(':app')
|
project.evaluationDependsOn(':app')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
org.gradle.jvmargs=-Xmx4G
|
org.gradle.jvmargs=-Xmx4G
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
android.defaults.buildfeatures.buildconfig=true
|
|
||||||
android.nonTransitiveRClass=false
|
|
||||||
android.nonFinalResIds=false
|
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
|
||||||
|
distributionSha256Sum=6001aba9b2204d26fa25a5800bb9382cf3ee01ccb78fe77317b2872336eb2f80
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version '8.6.0' apply false
|
id "com.android.application" version "7.4.2" apply false
|
||||||
id "org.jetbrains.kotlin.android" version "2.1.21" apply false
|
id "org.jetbrains.kotlin.android" version "1.8.10" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
include ":app"
|
include ":app"
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
variables:
|
|
||||||
output: dist/
|
|
||||||
releases:
|
|
||||||
- name: linux
|
|
||||||
jobs:
|
|
||||||
- name: release-linux-deb
|
|
||||||
package:
|
|
||||||
platform: linux
|
|
||||||
target: deb
|
|
||||||
- name: release-linux-rpm
|
|
||||||
package:
|
|
||||||
platform: linux
|
|
||||||
target: rpm
|
|
||||||
@@ -6,7 +6,7 @@ PODS:
|
|||||||
- file_picker (0.0.1):
|
- file_picker (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_native_splash (2.4.3):
|
- flutter_native_splash (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- icloud_storage (0.0.1):
|
- icloud_storage (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -31,6 +31,8 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- watch_connectivity (0.0.1):
|
- watch_connectivity (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- webview_flutter_wkwebview (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||||
@@ -48,6 +50,7 @@ DEPENDENCIES:
|
|||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
- watch_connectivity (from `.symlinks/plugins/watch_connectivity/ios`)
|
- watch_connectivity (from `.symlinks/plugins/watch_connectivity/ios`)
|
||||||
|
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
app_links:
|
app_links:
|
||||||
@@ -80,24 +83,27 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||||
watch_connectivity:
|
watch_connectivity:
|
||||||
:path: ".symlinks/plugins/watch_connectivity/ios"
|
:path: ".symlinks/plugins/watch_connectivity/ios"
|
||||||
|
webview_flutter_wkwebview:
|
||||||
|
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7
|
app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0
|
||||||
camera_avfoundation: be3be85408cd4126f250386828e9b1dfa40ab436
|
camera_avfoundation: dd002b0330f4981e1bbcb46ae9b62829237459a4
|
||||||
file_picker: fb04e739ae6239a76ce1f571863a196a922c87d4
|
file_picker: c79185e70b9b45728cde2a8d8da454e0cb43f287
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||||
icloud_storage: e55639f0c0d7cb2b0ba9c0b3d5968ccca9cd9aa2
|
icloud_storage: d9ac7a33ced81df08ba7ea1bf3099cc0ee58f60a
|
||||||
local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
|
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
|
||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
plain_notification_token: 047876b9d80a5b93565ddcc13a487a7e7b906f7d
|
plain_notification_token: b36467dc91939a7b6754267c701bbaca14996ee1
|
||||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
||||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||||
watch_connectivity: 88e5bea25b473e66ef8d3f960954d154ed0356d6
|
watch_connectivity: 715eb484685e05846eab74795348a44bb2809b82
|
||||||
|
webview_flutter_wkwebview: 2a23822e9039b7b1bc52e5add778e5d89ad488d1
|
||||||
|
|
||||||
PODFILE CHECKSUM: ec6ef69056f066e8b21a3391082f23b5ad2d37f8
|
PODFILE CHECKSUM: ec6ef69056f066e8b21a3391082f23b5ad2d37f8
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.15.2
|
||||||
|
|||||||
@@ -672,7 +672,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -682,7 +682,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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";
|
||||||
@@ -808,7 +808,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -818,7 +818,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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";
|
||||||
@@ -836,7 +836,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -846,7 +846,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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";
|
||||||
@@ -867,7 +867,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -880,7 +880,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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;
|
||||||
@@ -906,7 +906,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -919,7 +919,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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)";
|
||||||
@@ -942,7 +942,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -955,7 +955,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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)";
|
||||||
@@ -978,7 +978,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -990,7 +990,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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;
|
||||||
@@ -1019,7 +1019,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -1031,7 +1031,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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;
|
||||||
@@ -1057,7 +1057,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 = 1189;
|
CURRENT_PROJECT_VERSION = 1104;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -1069,7 +1069,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1189;
|
MARKETING_VERSION = 1.0.1104;
|
||||||
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;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
@@ -44,13 +43,11 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
enableGPUValidationMode = "1"
|
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
arb-dir: lib/l10n
|
arb-dir: lib/l10n
|
||||||
template-arb-file: app_en.arb
|
template-arb-file: app_en.arb
|
||||||
output-localization-file: l10n.dart
|
output-localization-file: l10n.dart
|
||||||
output-dir: lib/generated/l10n
|
|
||||||
synthetic-package: false
|
|
||||||
untranslated-messages-file: untranlated.json
|
untranslated-messages-file: untranlated.json
|
||||||
141
lib/app.dart
@@ -1,14 +1,14 @@
|
|||||||
import 'package:dynamic_color/dynamic_color.dart';
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:fl_lib/generated/l10n/lib_l10n.dart';
|
import 'package:fl_lib/l10n/gen_l10n/lib_l10n.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:responsive_framework/responsive_framework.dart';
|
|
||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
import 'package:server_box/data/res/build_data.dart';
|
import 'package:server_box/data/res/build_data.dart';
|
||||||
|
import 'package:server_box/data/res/rebuild.dart';
|
||||||
import 'package:server_box/data/res/store.dart';
|
import 'package:server_box/data/res/store.dart';
|
||||||
import 'package:server_box/generated/l10n/l10n.dart';
|
import 'package:server_box/view/page/home/home.dart';
|
||||||
import 'package:server_box/view/page/home.dart';
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
|
|
||||||
part 'intro.dart';
|
part 'intro.dart';
|
||||||
|
|
||||||
@@ -22,67 +22,48 @@ class MyApp extends StatelessWidget {
|
|||||||
listenable: RNodes.app,
|
listenable: RNodes.app,
|
||||||
builder: (context, _) {
|
builder: (context, _) {
|
||||||
if (!Stores.setting.useSystemPrimaryColor.fetch()) {
|
if (!Stores.setting.useSystemPrimaryColor.fetch()) {
|
||||||
return _build(context);
|
final colorSeed = Color(Stores.setting.colorSeed.fetch());
|
||||||
|
UIs.colorSeed = colorSeed;
|
||||||
|
// Past code uses [UIs.primaryColor] as the primary color
|
||||||
|
UIs.primaryColor = colorSeed;
|
||||||
|
return _buildApp(
|
||||||
|
context,
|
||||||
|
light: ThemeData(
|
||||||
|
useMaterial3: true,
|
||||||
|
colorSchemeSeed: UIs.colorSeed,
|
||||||
|
),
|
||||||
|
dark: ThemeData(
|
||||||
|
useMaterial3: true,
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
colorSchemeSeed: UIs.colorSeed,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
return DynamicColorBuilder(
|
||||||
return _buildDynamicColor(context);
|
builder: (light, dark) {
|
||||||
|
final lightTheme = ThemeData(
|
||||||
|
useMaterial3: true,
|
||||||
|
colorScheme: light,
|
||||||
|
);
|
||||||
|
final darkTheme = ThemeData(
|
||||||
|
useMaterial3: true,
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
colorScheme: dark,
|
||||||
|
);
|
||||||
|
if (context.isDark && dark != null) {
|
||||||
|
UIs.primaryColor = dark.primary;
|
||||||
|
} else if (!context.isDark && light != null) {
|
||||||
|
UIs.primaryColor = light.primary;
|
||||||
|
}
|
||||||
|
return _buildApp(context, light: lightTheme, dark: darkTheme);
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _build(BuildContext context) {
|
Widget _buildApp(BuildContext ctx,
|
||||||
final colorSeed = Color(Stores.setting.colorSeed.fetch());
|
{required ThemeData light, required ThemeData dark}) {
|
||||||
UIs.colorSeed = colorSeed;
|
|
||||||
UIs.primaryColor = colorSeed;
|
|
||||||
|
|
||||||
return _buildApp(
|
|
||||||
context,
|
|
||||||
light: ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
colorSchemeSeed: UIs.colorSeed,
|
|
||||||
appBarTheme: AppBarTheme(
|
|
||||||
scrolledUnderElevation: 0.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
dark: ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
colorSchemeSeed: UIs.colorSeed,
|
|
||||||
appBarTheme: AppBarTheme(
|
|
||||||
scrolledUnderElevation: 0.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDynamicColor(BuildContext context) {
|
|
||||||
return DynamicColorBuilder(
|
|
||||||
builder: (light, dark) {
|
|
||||||
final lightTheme = ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
colorScheme: light,
|
|
||||||
);
|
|
||||||
final darkTheme = ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
colorScheme: dark,
|
|
||||||
);
|
|
||||||
if (context.isDark && dark != null) {
|
|
||||||
UIs.primaryColor = dark.primary;
|
|
||||||
} else if (!context.isDark && light != null) {
|
|
||||||
UIs.primaryColor = light.primary;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buildApp(context, light: lightTheme, dark: darkTheme);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildApp(
|
|
||||||
BuildContext ctx, {
|
|
||||||
required ThemeData light,
|
|
||||||
required ThemeData dark,
|
|
||||||
}) {
|
|
||||||
final tMode = Stores.setting.themeMode.fetch();
|
final tMode = Stores.setting.themeMode.fetch();
|
||||||
// Issue #57
|
// Issue #57
|
||||||
final themeMode = switch (tMode) {
|
final themeMode = switch (tMode) {
|
||||||
@@ -94,14 +75,6 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
key: ValueKey(locale),
|
key: ValueKey(locale),
|
||||||
builder: (context, child) => ResponsiveBreakpoints.builder(
|
|
||||||
child: child ?? UIs.placeholder,
|
|
||||||
breakpoints: const [
|
|
||||||
Breakpoint(start: 0, end: 450, name: MOBILE),
|
|
||||||
Breakpoint(start: 451, end: 800, name: TABLET),
|
|
||||||
Breakpoint(start: 801, end: 1920, name: DESKTOP),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
locale: locale,
|
locale: locale,
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
LibLocalizations.delegate,
|
LibLocalizations.delegate,
|
||||||
@@ -114,25 +87,21 @@ class MyApp extends StatelessWidget {
|
|||||||
themeMode: themeMode,
|
themeMode: themeMode,
|
||||||
theme: light.fixWindowsFont,
|
theme: light.fixWindowsFont,
|
||||||
darkTheme: (tMode < 3 ? dark : dark.toAmoled).fixWindowsFont,
|
darkTheme: (tMode < 3 ? dark : dark.toAmoled).fixWindowsFont,
|
||||||
home: Builder(
|
home: VirtualWindowFrame(
|
||||||
builder: (context) {
|
child: Builder(
|
||||||
context.setLibL10n();
|
builder: (context) {
|
||||||
final appL10n = AppLocalizations.of(context);
|
context.setLibL10n();
|
||||||
if (appL10n != null) l10n = appL10n;
|
final appL10n = AppLocalizations.of(context);
|
||||||
|
if (appL10n != null) l10n = appL10n;
|
||||||
|
|
||||||
Widget child;
|
final intros = _IntroPage.builders;
|
||||||
final intros = _IntroPage.builders;
|
if (intros.isNotEmpty) {
|
||||||
if (intros.isNotEmpty) {
|
return _IntroPage(intros);
|
||||||
child = _IntroPage(intros);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
child = const HomePage();
|
return const HomePage();
|
||||||
|
},
|
||||||
return VirtualWindowFrame(
|
),
|
||||||
title: BuildData.name,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:server_box/data/res/misc.dart';
|
|
||||||
import 'package:server_box/data/res/store.dart';
|
|
||||||
|
|
||||||
abstract final class MethodChans {
|
|
||||||
static const _channel = MethodChannel('${Miscs.pkgName}/main_chan');
|
|
||||||
|
|
||||||
static void moveToBg() {
|
|
||||||
_channel.invokeMethod('sendToBackground');
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Issue #662
|
|
||||||
static void startService() {
|
|
||||||
// if (Stores.setting.fgService.fetch() != true) return;
|
|
||||||
// _channel.invokeMethod('startService');
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Issue #662
|
|
||||||
static void stopService() {
|
|
||||||
// if (Stores.setting.fgService.fetch() != true) return;
|
|
||||||
// _channel.invokeMethod('stopService');
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateHomeWidget() async {
|
|
||||||
if (!isIOS || !isAndroid) return;
|
|
||||||
if (!Stores.setting.autoUpdateHomeWidget.fetch()) return;
|
|
||||||
await _channel.invokeMethod('updateHomeWidget');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
18
lib/core/channel/bg_run.dart
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:server_box/data/res/misc.dart';
|
||||||
|
|
||||||
|
abstract final class BgRunMC {
|
||||||
|
static const _channel = MethodChannel('${Miscs.pkgName}/app_retain');
|
||||||
|
|
||||||
|
static void moveToBg() {
|
||||||
|
_channel.invokeMethod('sendToBackground');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startService() {
|
||||||
|
_channel.invokeMethod('startService');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stopService() {
|
||||||
|
_channel.invokeMethod('stopService');
|
||||||
|
}
|
||||||
|
}
|
||||||
12
lib/core/channel/home_widget.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:server_box/data/res/misc.dart';
|
||||||
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
|
||||||
|
abstract final class HomeWidgetMC {
|
||||||
|
static const _channel = MethodChannel('${Miscs.pkgName}/home_widget');
|
||||||
|
|
||||||
|
static void update() {
|
||||||
|
if (!Stores.setting.autoUpdateHomeWidget.fetch()) return;
|
||||||
|
_channel.invokeMethod('update');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:server_box/generated/l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n_en.dart';
|
||||||
import 'package:server_box/generated/l10n/l10n_en.dart';
|
|
||||||
|
|
||||||
AppLocalizations l10n = AppLocalizationsEn();
|
AppLocalizations l10n = AppLocalizationsEn();
|
||||||
|
|
||||||
extension LocaleX on BuildContext {
|
|
||||||
AppLocalizations get l10n => AppLocalizations.of(this)!;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,17 +12,17 @@ extension SftpFileX on SftpFileMode {
|
|||||||
|
|
||||||
UnixPerm toUnixPerm() {
|
UnixPerm toUnixPerm() {
|
||||||
return UnixPerm(
|
return UnixPerm(
|
||||||
user: UnixPermOp(
|
user: RWX(
|
||||||
r: userRead,
|
r: userRead,
|
||||||
w: userWrite,
|
w: userWrite,
|
||||||
x: userExecute,
|
x: userExecute,
|
||||||
),
|
),
|
||||||
group: UnixPermOp(
|
group: RWX(
|
||||||
r: groupRead,
|
r: groupRead,
|
||||||
w: groupWrite,
|
w: groupWrite,
|
||||||
x: groupExecute,
|
x: groupExecute,
|
||||||
),
|
),
|
||||||
other: UnixPermOp(
|
other: RWX(
|
||||||
r: otherRead,
|
r: otherRead,
|
||||||
w: otherWrite,
|
w: otherWrite,
|
||||||
x: otherExecute,
|
x: otherExecute,
|
||||||
|
|||||||
@@ -1,9 +1,169 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:server_box/data/model/server/private_key_info.dart';
|
||||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||||
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
import 'package:server_box/view/page/container.dart';
|
||||||
|
import 'package:server_box/view/page/home/home.dart';
|
||||||
|
import 'package:server_box/view/page/iperf.dart';
|
||||||
|
import 'package:server_box/view/page/ping.dart';
|
||||||
|
import 'package:server_box/view/page/private_key/edit.dart';
|
||||||
|
import 'package:server_box/view/page/pve.dart';
|
||||||
|
import 'package:server_box/view/page/server/detail/view.dart';
|
||||||
|
import 'package:server_box/view/page/setting/platform/android.dart';
|
||||||
|
import 'package:server_box/view/page/setting/platform/ios.dart';
|
||||||
|
import 'package:server_box/view/page/setting/seq/srv_func_seq.dart';
|
||||||
|
import 'package:server_box/view/page/snippet/result.dart';
|
||||||
|
import 'package:server_box/view/page/ssh/page.dart';
|
||||||
|
import 'package:server_box/view/page/setting/seq/virt_key.dart';
|
||||||
|
import 'package:server_box/data/model/server/snippet.dart';
|
||||||
|
import 'package:server_box/view/page/process.dart';
|
||||||
|
import 'package:server_box/view/page/server/tab.dart';
|
||||||
|
import 'package:server_box/view/page/setting/seq/srv_detail_seq.dart';
|
||||||
|
import 'package:server_box/view/page/setting/seq/srv_seq.dart';
|
||||||
|
import 'package:server_box/view/page/snippet/edit.dart';
|
||||||
|
import 'package:server_box/view/page/storage/sftp.dart';
|
||||||
|
import 'package:server_box/view/page/storage/sftp_mission.dart';
|
||||||
|
|
||||||
/// The args class for [AppRoute].
|
class AppRoutes {
|
||||||
final class SpiRequiredArgs {
|
final Widget page;
|
||||||
/// The only required argument for this class.
|
final String title;
|
||||||
final Spi spi;
|
|
||||||
|
|
||||||
const SpiRequiredArgs(this.spi);
|
AppRoutes(this.page, this.title);
|
||||||
|
|
||||||
|
Future<T?> go<T>(BuildContext context) {
|
||||||
|
return Navigator.push<T>(
|
||||||
|
context,
|
||||||
|
Stores.setting.cupertinoRoute.fetch()
|
||||||
|
? CupertinoPageRoute(builder: (context) => page)
|
||||||
|
: MaterialPageRoute(builder: (context) => page),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<T?> checkGo<T>({
|
||||||
|
required BuildContext context,
|
||||||
|
required bool Function() check,
|
||||||
|
}) {
|
||||||
|
if (check()) {
|
||||||
|
return go(context);
|
||||||
|
}
|
||||||
|
return Future.value(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes serverDetail({Key? key, required Spi spi}) {
|
||||||
|
return AppRoutes(ServerDetailPage(key: key, spi: spi), 'server_detail');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes serverTab({Key? key}) {
|
||||||
|
return AppRoutes(ServerPage(key: key), 'server_tab');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes keyEdit({Key? key, PrivateKeyInfo? pki}) {
|
||||||
|
return AppRoutes(
|
||||||
|
PrivateKeyEditPage(pki: pki),
|
||||||
|
'key_${pki == null ? 'add' : 'edit'}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes snippetEdit({Key? key, Snippet? snippet}) {
|
||||||
|
return AppRoutes(
|
||||||
|
SnippetEditPage(snippet: snippet),
|
||||||
|
'snippet_${snippet == null ? 'add' : 'edit'}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes ssh({
|
||||||
|
Key? key,
|
||||||
|
required Spi spi,
|
||||||
|
String? initCmd,
|
||||||
|
Snippet? initSnippet,
|
||||||
|
}) {
|
||||||
|
return AppRoutes(
|
||||||
|
SSHPage(
|
||||||
|
key: key,
|
||||||
|
spi: spi,
|
||||||
|
initCmd: initCmd,
|
||||||
|
initSnippet: initSnippet,
|
||||||
|
),
|
||||||
|
'ssh_term',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes sshVirtKeySetting({Key? key}) {
|
||||||
|
return AppRoutes(SSHVirtKeySettingPage(key: key), 'ssh_virt_key_setting');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes sftpMission({Key? key}) {
|
||||||
|
return AppRoutes(SftpMissionPage(key: key), 'sftp_mission');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes sftp(
|
||||||
|
{Key? key, required Spi spi, String? initPath, bool isSelect = false}) {
|
||||||
|
return AppRoutes(
|
||||||
|
SftpPage(
|
||||||
|
key: key,
|
||||||
|
spi: spi,
|
||||||
|
initPath: initPath,
|
||||||
|
isSelect: isSelect,
|
||||||
|
),
|
||||||
|
'sftp');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes docker({Key? key, required Spi spi}) {
|
||||||
|
return AppRoutes(ContainerPage(key: key, spi: spi), 'docker');
|
||||||
|
}
|
||||||
|
|
||||||
|
// static AppRoutes fullscreen({Key? key}) {
|
||||||
|
// return AppRoutes(FullScreenPage(key: key), 'fullscreen');
|
||||||
|
// }
|
||||||
|
|
||||||
|
static AppRoutes home({Key? key}) {
|
||||||
|
return AppRoutes(HomePage(key: key), 'home');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes ping({Key? key}) {
|
||||||
|
return AppRoutes(PingPage(key: key), 'ping');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes process({Key? key, required Spi spi}) {
|
||||||
|
return AppRoutes(ProcessPage(key: key, spi: spi), 'process');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes serverOrder({Key? key}) {
|
||||||
|
return AppRoutes(ServerOrderPage(key: key), 'server_order');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes serverDetailOrder({Key? key}) {
|
||||||
|
return AppRoutes(ServerDetailOrderPage(key: key), 'server_detail_order');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes iosSettings({Key? key}) {
|
||||||
|
return AppRoutes(IOSSettingsPage(key: key), 'ios_setting');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes androidSettings({Key? key}) {
|
||||||
|
return AppRoutes(AndroidSettingsPage(key: key), 'android_setting');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes snippetResult(
|
||||||
|
{Key? key, required List<SnippetResult?> results}) {
|
||||||
|
return AppRoutes(
|
||||||
|
SnippetResultPage(
|
||||||
|
key: key,
|
||||||
|
results: results,
|
||||||
|
),
|
||||||
|
'snippet_result');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes iperf({Key? key, required Spi spi}) {
|
||||||
|
return AppRoutes(IPerfPage(key: key, spi: spi), 'iperf');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes serverFuncBtnsOrder({Key? key}) {
|
||||||
|
return AppRoutes(ServerFuncBtnsOrderPage(key: key), 'server_func_btns_seq');
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppRoutes pve({Key? key, required Spi spi}) {
|
||||||
|
return AppRoutes(PvePage(key: key, spi: spi), 'pve');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,39 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:server_box/data/model/app/bak/backup2.dart';
|
import 'package:server_box/data/model/app/backup.dart';
|
||||||
import 'package:server_box/data/model/app/bak/utils.dart';
|
import 'package:server_box/data/store/no_backup.dart';
|
||||||
|
|
||||||
const bakSync = BakSyncer._();
|
const bakSync = BakSyncer._();
|
||||||
|
|
||||||
final icloud = ICloud(containerId: 'iCloud.tech.lolli.serverbox');
|
final class BakSyncer extends SyncIface<Backup> {
|
||||||
|
|
||||||
final class BakSyncer extends SyncIface {
|
|
||||||
const BakSyncer._() : super();
|
const BakSyncer._() : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> saveToFile() => BackupV2.backup();
|
Future<void> saveToFile() => Backup.backup();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Mergeable> fromFile(String path) async {
|
Future<Backup> fromFile(String path) async {
|
||||||
final content = await File(path).readAsString();
|
final content = await File(path).readAsString();
|
||||||
return MergeableUtils.fromJsonString(content).$1;
|
return Backup.fromJsonString(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
RemoteStorage? get remoteStorage {
|
Future<RemoteStorage?> get remoteStorage async {
|
||||||
final icloudEnabled = PrefProps.icloudSync.get();
|
if (isMacOS || isIOS) await icloud.init('iCloud.tech.lolli.serverbox');
|
||||||
|
final settings = NoBackupStore.instance;
|
||||||
|
await webdav.init(WebdavInitArgs(
|
||||||
|
url: settings.webdavUrl.fetch(),
|
||||||
|
user: settings.webdavUser.fetch(),
|
||||||
|
pwd: settings.webdavPwd.fetch(),
|
||||||
|
prefix: 'serverbox/',
|
||||||
|
));
|
||||||
|
|
||||||
|
final icloudEnabled = settings.icloudSync.fetch();
|
||||||
if (icloudEnabled) return icloud;
|
if (icloudEnabled) return icloud;
|
||||||
|
|
||||||
final webdavEnabled = PrefProps.webdavSync.get();
|
final webdavEnabled = settings.webdavSync.fetch();
|
||||||
if (webdavEnabled) return Webdav.shared;
|
if (webdavEnabled) return webdav;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import 'package:dartssh2/dartssh2.dart';
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:server_box/data/model/app/error.dart';
|
import 'package:server_box/data/model/app/error.dart';
|
||||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
|
||||||
import 'package:server_box/data/res/store.dart';
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
|
||||||
|
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||||
|
|
||||||
/// Must put this func out of any Class.
|
/// Must put this func out of any Class.
|
||||||
///
|
///
|
||||||
/// Because of this function is called by [compute].
|
/// Because of this function is called by [compute].
|
||||||
@@ -31,7 +32,7 @@ enum GenSSHClientStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String getPrivateKey(String id) {
|
String getPrivateKey(String id) {
|
||||||
final pki = Stores.key.fetchOne(id);
|
final pki = Stores.key.get(id);
|
||||||
if (pki == null) {
|
if (pki == null) {
|
||||||
throw SSHErr(
|
throw SSHErr(
|
||||||
type: SSHErrType.noPrivateKey,
|
type: SSHErrType.noPrivateKey,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:server_box/data/model/server/private_key_info.dart';
|
|||||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||||
import 'package:server_box/data/model/server/snippet.dart';
|
import 'package:server_box/data/model/server/snippet.dart';
|
||||||
import 'package:server_box/data/res/misc.dart';
|
import 'package:server_box/data/res/misc.dart';
|
||||||
|
import 'package:server_box/data/res/rebuild.dart';
|
||||||
import 'package:server_box/data/res/store.dart';
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
|
||||||
part 'backup.g.dart';
|
part 'backup.g.dart';
|
||||||
@@ -45,24 +46,19 @@ class Backup implements Mergeable {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() => _$BackupToJson(this);
|
Map<String, dynamic> toJson() => _$BackupToJson(this);
|
||||||
|
|
||||||
static Future<Backup> loadFromStore() async {
|
Backup.loadFromStore()
|
||||||
final lastModTime = Stores.lastModTime;
|
: version = backupFormatVersion,
|
||||||
return Backup(
|
date = DateTime.now().toString().split('.').firstOrNull ?? '',
|
||||||
version: backupFormatVersion,
|
spis = Stores.server.fetch(),
|
||||||
date: DateTime.now().toString().split('.').firstOrNull ?? '',
|
snippets = Stores.snippet.fetch(),
|
||||||
spis: Stores.server.fetch(),
|
keys = Stores.key.fetch(),
|
||||||
snippets: Stores.snippet.fetch(),
|
container = Stores.container.box.toJson(),
|
||||||
keys: Stores.key.fetch(),
|
lastModTime = Stores.lastModTime,
|
||||||
container: Stores.container.getAllMap(),
|
history = Stores.history.box.toJson(),
|
||||||
lastModTime: lastModTime,
|
settings = Stores.setting.box.toJson();
|
||||||
history: Stores.history.getAllMap(),
|
|
||||||
settings: Stores.setting.getAllMap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<String> backup([String? name]) async {
|
static Future<String> backup([String? name]) async {
|
||||||
final bak = await Backup.loadFromStore();
|
final result = _diyEncrypt(json.encode(Backup.loadFromStore().toJson()));
|
||||||
final result = _diyEncrypt(json.encode(bak.toJson()));
|
|
||||||
final path = Paths.doc.joinPath(name ?? Miscs.bakFileName);
|
final path = Paths.doc.joinPath(name ?? Miscs.bakFileName);
|
||||||
await File(path).writeAsString(result);
|
await File(path).writeAsString(result);
|
||||||
return path;
|
return path;
|
||||||
@@ -70,7 +66,7 @@ class Backup implements Mergeable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> merge({bool force = false}) async {
|
Future<void> merge({bool force = false}) async {
|
||||||
final curTime = Stores.lastModTime;
|
final curTime = Stores.lastModTime ?? 0;
|
||||||
final bakTime = lastModTime ?? 0;
|
final bakTime = lastModTime ?? 0;
|
||||||
final shouldRestore = force || curTime < bakTime;
|
final shouldRestore = force || curTime < bakTime;
|
||||||
if (!shouldRestore) {
|
if (!shouldRestore) {
|
||||||
@@ -234,4 +230,3 @@ String _diyDecrypt(String raw) {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
37
lib/data/model/app/backup.g.dart
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'backup.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
Backup _$BackupFromJson(Map<String, dynamic> json) => Backup(
|
||||||
|
version: (json['version'] as num).toInt(),
|
||||||
|
date: json['date'] as String,
|
||||||
|
spis: (json['spis'] as List<dynamic>)
|
||||||
|
.map((e) => Spi.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
snippets: (json['snippets'] as List<dynamic>)
|
||||||
|
.map((e) => Snippet.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
keys: (json['keys'] as List<dynamic>)
|
||||||
|
.map((e) => PrivateKeyInfo.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
container: json['container'] as Map<String, dynamic>,
|
||||||
|
history: json['history'] as Map<String, dynamic>,
|
||||||
|
settings: json['settings'] as Map<String, dynamic>?,
|
||||||
|
lastModTime: (json['lastModTime'] as num?)?.toInt(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$BackupToJson(Backup instance) => <String, dynamic>{
|
||||||
|
'version': instance.version,
|
||||||
|
'date': instance.date,
|
||||||
|
'spis': instance.spis,
|
||||||
|
'snippets': instance.snippets,
|
||||||
|
'keys': instance.keys,
|
||||||
|
'container': instance.container,
|
||||||
|
'history': instance.history,
|
||||||
|
'lastModTime': instance.lastModTime,
|
||||||
|
'settings': instance.settings,
|
||||||
|
};
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'backup.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
Backup _$BackupFromJson(Map<String, dynamic> json) => Backup(
|
|
||||||
version: (json['version'] as num).toInt(),
|
|
||||||
date: json['date'] as String,
|
|
||||||
spis: (json['spis'] as List<dynamic>)
|
|
||||||
.map((e) => Spi.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
snippets: (json['snippets'] as List<dynamic>)
|
|
||||||
.map((e) => Snippet.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
keys: (json['keys'] as List<dynamic>)
|
|
||||||
.map((e) => PrivateKeyInfo.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
container: json['container'] as Map<String, dynamic>,
|
|
||||||
history: json['history'] as Map<String, dynamic>,
|
|
||||||
settings: json['settings'] as Map<String, dynamic>?,
|
|
||||||
lastModTime: (json['lastModTime'] as num?)?.toInt(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$BackupToJson(Backup instance) => <String, dynamic>{
|
|
||||||
'version': instance.version,
|
|
||||||
'date': instance.date,
|
|
||||||
'spis': instance.spis,
|
|
||||||
'snippets': instance.snippets,
|
|
||||||
'keys': instance.keys,
|
|
||||||
'container': instance.container,
|
|
||||||
'history': instance.history,
|
|
||||||
'lastModTime': instance.lastModTime,
|
|
||||||
'settings': instance.settings,
|
|
||||||
};
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:server_box/data/res/misc.dart';
|
|
||||||
import 'package:server_box/data/res/store.dart';
|
|
||||||
|
|
||||||
part 'backup2.freezed.dart';
|
|
||||||
part 'backup2.g.dart';
|
|
||||||
|
|
||||||
final _loggerV2 = Logger('BackupV2');
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class BackupV2 with _$BackupV2 implements Mergeable {
|
|
||||||
const BackupV2._();
|
|
||||||
|
|
||||||
/// Construct a backup with the latest format (v2).
|
|
||||||
///
|
|
||||||
/// All `Map<String, dynamic>` are:
|
|
||||||
/// ```json
|
|
||||||
/// {
|
|
||||||
/// "key1": Model{},
|
|
||||||
/// "_lastModTime": {
|
|
||||||
/// "key1": 1234567890,
|
|
||||||
/// },
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
const factory BackupV2({
|
|
||||||
required int version,
|
|
||||||
required int date,
|
|
||||||
required Map<String, Object?> spis,
|
|
||||||
required Map<String, Object?> snippets,
|
|
||||||
required Map<String, Object?> keys,
|
|
||||||
required Map<String, Object?> container,
|
|
||||||
required Map<String, Object?> history,
|
|
||||||
required Map<String, Object?> settings,
|
|
||||||
}) = _BackupV2;
|
|
||||||
|
|
||||||
factory BackupV2.fromJson(Map<String, dynamic> json) => _$BackupV2FromJson(json);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> merge({bool force = false}) async {
|
|
||||||
_loggerV2.info('Merging...');
|
|
||||||
|
|
||||||
// Merge each store
|
|
||||||
await Mergeable.mergeStore(backupData: spis, store: Stores.server, force: force);
|
|
||||||
await Mergeable.mergeStore(backupData: snippets, store: Stores.snippet, force: force);
|
|
||||||
await Mergeable.mergeStore(backupData: keys, store: Stores.key, force: force);
|
|
||||||
await Mergeable.mergeStore(backupData: container, store: Stores.container, force: force);
|
|
||||||
await Mergeable.mergeStore(backupData: history, store: Stores.history, force: force);
|
|
||||||
await Mergeable.mergeStore(backupData: settings, store: Stores.setting, force: force);
|
|
||||||
|
|
||||||
// Reload providers and notify listeners
|
|
||||||
Provider.reload();
|
|
||||||
RNodes.app.notify();
|
|
||||||
|
|
||||||
_loggerV2.info('Merge completed');
|
|
||||||
}
|
|
||||||
|
|
||||||
static const formatVer = 2;
|
|
||||||
|
|
||||||
static Future<BackupV2> loadFromStore() async {
|
|
||||||
return BackupV2(
|
|
||||||
version: formatVer,
|
|
||||||
date: DateTimeX.timestamp,
|
|
||||||
spis: Stores.server.getAllMap(includeInternalKeys: true),
|
|
||||||
snippets: Stores.snippet.getAllMap(includeInternalKeys: true),
|
|
||||||
keys: Stores.key.getAllMap(includeInternalKeys: true),
|
|
||||||
container: Stores.container.getAllMap(includeInternalKeys: true),
|
|
||||||
history: Stores.history.getAllMap(includeInternalKeys: true),
|
|
||||||
settings: Stores.setting.getAllMap(includeInternalKeys: true),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<String> backup([String? name]) async {
|
|
||||||
final bak = await BackupV2.loadFromStore();
|
|
||||||
final result = json.encode(bak.toJson());
|
|
||||||
final path = Paths.doc.joinPath(name ?? Miscs.bakFileName);
|
|
||||||
await File(path).writeAsString(result);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
factory BackupV2.fromJsonString(String jsonString) {
|
|
||||||
final map = json.decode(jsonString) as Map<String, dynamic>;
|
|
||||||
return BackupV2.fromJson(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
// dart format width=80
|
|
||||||
// coverage:ignore-file
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
|
||||||
|
|
||||||
part of 'backup2.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// dart format off
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$BackupV2 {
|
|
||||||
|
|
||||||
int get version; int get date; Map<String, Object?> get spis; Map<String, Object?> get snippets; Map<String, Object?> get keys; Map<String, Object?> get container; Map<String, Object?> get history; Map<String, Object?> get settings;
|
|
||||||
/// Create a copy of BackupV2
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$BackupV2CopyWith<BackupV2> get copyWith => _$BackupV2CopyWithImpl<BackupV2>(this as BackupV2, _$identity);
|
|
||||||
|
|
||||||
/// Serializes this BackupV2 to a JSON map.
|
|
||||||
Map<String, dynamic> toJson();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is BackupV2&&(identical(other.version, version) || other.version == version)&&(identical(other.date, date) || other.date == date)&&const DeepCollectionEquality().equals(other.spis, spis)&&const DeepCollectionEquality().equals(other.snippets, snippets)&&const DeepCollectionEquality().equals(other.keys, keys)&&const DeepCollectionEquality().equals(other.container, container)&&const DeepCollectionEquality().equals(other.history, history)&&const DeepCollectionEquality().equals(other.settings, settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,version,date,const DeepCollectionEquality().hash(spis),const DeepCollectionEquality().hash(snippets),const DeepCollectionEquality().hash(keys),const DeepCollectionEquality().hash(container),const DeepCollectionEquality().hash(history),const DeepCollectionEquality().hash(settings));
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'BackupV2(version: $version, date: $date, spis: $spis, snippets: $snippets, keys: $keys, container: $container, history: $history, settings: $settings)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $BackupV2CopyWith<$Res> {
|
|
||||||
factory $BackupV2CopyWith(BackupV2 value, $Res Function(BackupV2) _then) = _$BackupV2CopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
int version, int date, Map<String, Object?> spis, Map<String, Object?> snippets, Map<String, Object?> keys, Map<String, Object?> container, Map<String, Object?> history, Map<String, Object?> settings
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$BackupV2CopyWithImpl<$Res>
|
|
||||||
implements $BackupV2CopyWith<$Res> {
|
|
||||||
_$BackupV2CopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final BackupV2 _self;
|
|
||||||
final $Res Function(BackupV2) _then;
|
|
||||||
|
|
||||||
/// Create a copy of BackupV2
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? version = null,Object? date = null,Object? spis = null,Object? snippets = null,Object? keys = null,Object? container = null,Object? history = null,Object? settings = null,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
version: null == version ? _self.version : version // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,spis: null == spis ? _self.spis : spis // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,snippets: null == snippets ? _self.snippets : snippets // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,keys: null == keys ? _self.keys : keys // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,container: null == container ? _self.container : container // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,history: null == history ? _self.history : history // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,settings: null == settings ? _self.settings : settings // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@JsonSerializable()
|
|
||||||
|
|
||||||
class _BackupV2 extends BackupV2 {
|
|
||||||
const _BackupV2({required this.version, required this.date, required final Map<String, Object?> spis, required final Map<String, Object?> snippets, required final Map<String, Object?> keys, required final Map<String, Object?> container, required final Map<String, Object?> history, required final Map<String, Object?> settings}): _spis = spis,_snippets = snippets,_keys = keys,_container = container,_history = history,_settings = settings,super._();
|
|
||||||
factory _BackupV2.fromJson(Map<String, dynamic> json) => _$BackupV2FromJson(json);
|
|
||||||
|
|
||||||
@override final int version;
|
|
||||||
@override final int date;
|
|
||||||
final Map<String, Object?> _spis;
|
|
||||||
@override Map<String, Object?> get spis {
|
|
||||||
if (_spis is EqualUnmodifiableMapView) return _spis;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_spis);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Object?> _snippets;
|
|
||||||
@override Map<String, Object?> get snippets {
|
|
||||||
if (_snippets is EqualUnmodifiableMapView) return _snippets;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_snippets);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Object?> _keys;
|
|
||||||
@override Map<String, Object?> get keys {
|
|
||||||
if (_keys is EqualUnmodifiableMapView) return _keys;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Object?> _container;
|
|
||||||
@override Map<String, Object?> get container {
|
|
||||||
if (_container is EqualUnmodifiableMapView) return _container;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_container);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Object?> _history;
|
|
||||||
@override Map<String, Object?> get history {
|
|
||||||
if (_history is EqualUnmodifiableMapView) return _history;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_history);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Object?> _settings;
|
|
||||||
@override Map<String, Object?> get settings {
|
|
||||||
if (_settings is EqualUnmodifiableMapView) return _settings;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Create a copy of BackupV2
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$BackupV2CopyWith<_BackupV2> get copyWith => __$BackupV2CopyWithImpl<_BackupV2>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$BackupV2ToJson(this, );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _BackupV2&&(identical(other.version, version) || other.version == version)&&(identical(other.date, date) || other.date == date)&&const DeepCollectionEquality().equals(other._spis, _spis)&&const DeepCollectionEquality().equals(other._snippets, _snippets)&&const DeepCollectionEquality().equals(other._keys, _keys)&&const DeepCollectionEquality().equals(other._container, _container)&&const DeepCollectionEquality().equals(other._history, _history)&&const DeepCollectionEquality().equals(other._settings, _settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,version,date,const DeepCollectionEquality().hash(_spis),const DeepCollectionEquality().hash(_snippets),const DeepCollectionEquality().hash(_keys),const DeepCollectionEquality().hash(_container),const DeepCollectionEquality().hash(_history),const DeepCollectionEquality().hash(_settings));
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'BackupV2(version: $version, date: $date, spis: $spis, snippets: $snippets, keys: $keys, container: $container, history: $history, settings: $settings)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$BackupV2CopyWith<$Res> implements $BackupV2CopyWith<$Res> {
|
|
||||||
factory _$BackupV2CopyWith(_BackupV2 value, $Res Function(_BackupV2) _then) = __$BackupV2CopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
int version, int date, Map<String, Object?> spis, Map<String, Object?> snippets, Map<String, Object?> keys, Map<String, Object?> container, Map<String, Object?> history, Map<String, Object?> settings
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$BackupV2CopyWithImpl<$Res>
|
|
||||||
implements _$BackupV2CopyWith<$Res> {
|
|
||||||
__$BackupV2CopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _BackupV2 _self;
|
|
||||||
final $Res Function(_BackupV2) _then;
|
|
||||||
|
|
||||||
/// Create a copy of BackupV2
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? version = null,Object? date = null,Object? spis = null,Object? snippets = null,Object? keys = null,Object? container = null,Object? history = null,Object? settings = null,}) {
|
|
||||||
return _then(_BackupV2(
|
|
||||||
version: null == version ? _self.version : version // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,spis: null == spis ? _self._spis : spis // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,snippets: null == snippets ? _self._snippets : snippets // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,keys: null == keys ? _self._keys : keys // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,container: null == container ? _self._container : container // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,history: null == history ? _self._history : history // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,settings: null == settings ? _self._settings : settings // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, Object?>,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// dart format on
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'backup2.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
_BackupV2 _$BackupV2FromJson(Map<String, dynamic> json) => _BackupV2(
|
|
||||||
version: (json['version'] as num).toInt(),
|
|
||||||
date: (json['date'] as num).toInt(),
|
|
||||||
spis: json['spis'] as Map<String, dynamic>,
|
|
||||||
snippets: json['snippets'] as Map<String, dynamic>,
|
|
||||||
keys: json['keys'] as Map<String, dynamic>,
|
|
||||||
container: json['container'] as Map<String, dynamic>,
|
|
||||||
history: json['history'] as Map<String, dynamic>,
|
|
||||||
settings: json['settings'] as Map<String, dynamic>,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$BackupV2ToJson(_BackupV2 instance) => <String, dynamic>{
|
|
||||||
'version': instance.version,
|
|
||||||
'date': instance.date,
|
|
||||||
'spis': instance.spis,
|
|
||||||
'snippets': instance.snippets,
|
|
||||||
'keys': instance.keys,
|
|
||||||
'container': instance.container,
|
|
||||||
'history': instance.history,
|
|
||||||
'settings': instance.settings,
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
|
||||||
import 'package:server_box/data/model/app/bak/backup.dart';
|
|
||||||
import 'package:server_box/data/model/app/bak/backup2.dart';
|
|
||||||
|
|
||||||
abstract final class MergeableUtils {
|
|
||||||
static (Mergeable, String) fromJsonString(String json) {
|
|
||||||
try {
|
|
||||||
final bak = BackupV2.fromJsonString(json);
|
|
||||||
return (bak, DateTime.fromMillisecondsSinceEpoch(bak.date).hms());
|
|
||||||
} catch (e) {
|
|
||||||
final bak = Backup.fromJsonString(json);
|
|
||||||
return (bak, bak.date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,27 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
|
||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
|
|
||||||
|
enum ErrFrom {
|
||||||
|
unknown,
|
||||||
|
apt,
|
||||||
|
docker,
|
||||||
|
sftp,
|
||||||
|
ssh,
|
||||||
|
status,
|
||||||
|
icloud,
|
||||||
|
webdav,
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Err<T> {
|
||||||
|
final ErrFrom from;
|
||||||
|
final T type;
|
||||||
|
final String? message;
|
||||||
|
|
||||||
|
String? get solution;
|
||||||
|
|
||||||
|
Err({required this.from, required this.type, this.message});
|
||||||
|
}
|
||||||
|
|
||||||
enum SSHErrType {
|
enum SSHErrType {
|
||||||
unknown,
|
unknown,
|
||||||
connect,
|
connect,
|
||||||
@@ -14,7 +35,7 @@ enum SSHErrType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SSHErr extends Err<SSHErrType> {
|
class SSHErr extends Err<SSHErrType> {
|
||||||
SSHErr({required super.type, super.message});
|
SSHErr({required super.type, super.message}) : super(from: ErrFrom.ssh);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get solution => switch (type) {
|
String? get solution => switch (type) {
|
||||||
@@ -24,6 +45,11 @@ class SSHErr extends Err<SSHErrType> {
|
|||||||
SSHErrType.noPrivateKey => l10n.noPrivateKeyTip,
|
SSHErrType.noPrivateKey => l10n.noPrivateKeyTip,
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SSHErr<$type>: $message';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ContainerErrType {
|
enum ContainerErrType {
|
||||||
@@ -39,10 +65,16 @@ enum ContainerErrType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ContainerErr extends Err<ContainerErrType> {
|
class ContainerErr extends Err<ContainerErrType> {
|
||||||
ContainerErr({required super.type, super.message});
|
ContainerErr({required super.type, super.message})
|
||||||
|
: super(from: ErrFrom.docker);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get solution => null;
|
String? get solution => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ContainerErr<$type>: $message';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ICloudErrType {
|
enum ICloudErrType {
|
||||||
@@ -52,10 +84,15 @@ enum ICloudErrType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ICloudErr extends Err<ICloudErrType> {
|
class ICloudErr extends Err<ICloudErrType> {
|
||||||
ICloudErr({required super.type, super.message});
|
ICloudErr({required super.type, super.message}) : super(from: ErrFrom.icloud);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get solution => null;
|
String? get solution => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ICloudErr<$type>: $message';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WebdavErrType {
|
enum WebdavErrType {
|
||||||
@@ -65,10 +102,15 @@ enum WebdavErrType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class WebdavErr extends Err<WebdavErrType> {
|
class WebdavErr extends Err<WebdavErrType> {
|
||||||
WebdavErr({required super.type, super.message});
|
WebdavErr({required super.type, super.message}) : super(from: ErrFrom.webdav);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get solution => null;
|
String? get solution => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'WebdavErr<$type>: $message';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PveErrType {
|
enum PveErrType {
|
||||||
@@ -79,8 +121,13 @@ enum PveErrType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PveErr extends Err<PveErrType> {
|
class PveErr extends Err<PveErrType> {
|
||||||
PveErr({required super.type, super.message});
|
PveErr({required super.type, super.message}) : super(from: ErrFrom.status);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get solution => null;
|
String? get solution => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'PveErr<$type>: $message';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,36 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
import 'package:server_box/data/res/store.dart';
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
|
||||||
|
part 'server_func.g.dart';
|
||||||
|
|
||||||
|
@HiveType(typeId: 6)
|
||||||
enum ServerFuncBtn {
|
enum ServerFuncBtn {
|
||||||
terminal(),
|
@HiveField(0)
|
||||||
sftp(),
|
terminal._(),
|
||||||
container(),
|
@HiveField(1)
|
||||||
process(),
|
sftp._(),
|
||||||
//pkg(),
|
@HiveField(2)
|
||||||
snippet(),
|
container._(),
|
||||||
iperf(),
|
@HiveField(3)
|
||||||
// pve(),
|
process._(),
|
||||||
systemd(1058),
|
//@HiveField(4)
|
||||||
|
//pkg,
|
||||||
|
@HiveField(5)
|
||||||
|
snippet._(),
|
||||||
|
@HiveField(6)
|
||||||
|
iperf._(),
|
||||||
|
// @HiveField(7)
|
||||||
|
// pve,
|
||||||
|
@HiveField(8)
|
||||||
|
systemd._(1058),
|
||||||
;
|
;
|
||||||
|
|
||||||
final int? addedVersion;
|
final int? addedVersion;
|
||||||
|
|
||||||
const ServerFuncBtn([this.addedVersion]);
|
const ServerFuncBtn._([this.addedVersion]);
|
||||||
|
|
||||||
static void autoAddNewFuncs(int cur) {
|
static void autoAddNewFuncs(int cur) {
|
||||||
if (cur >= systemd.addedVersion!) {
|
if (cur >= systemd.addedVersion!) {
|
||||||
|
|||||||
71
lib/data/model/app/menu/server_func.g.dart
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'server_func.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class ServerFuncBtnAdapter extends TypeAdapter<ServerFuncBtn> {
|
||||||
|
@override
|
||||||
|
final int typeId = 6;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ServerFuncBtn read(BinaryReader reader) {
|
||||||
|
switch (reader.readByte()) {
|
||||||
|
case 0:
|
||||||
|
return ServerFuncBtn.terminal;
|
||||||
|
case 1:
|
||||||
|
return ServerFuncBtn.sftp;
|
||||||
|
case 2:
|
||||||
|
return ServerFuncBtn.container;
|
||||||
|
case 3:
|
||||||
|
return ServerFuncBtn.process;
|
||||||
|
case 5:
|
||||||
|
return ServerFuncBtn.snippet;
|
||||||
|
case 6:
|
||||||
|
return ServerFuncBtn.iperf;
|
||||||
|
case 8:
|
||||||
|
return ServerFuncBtn.systemd;
|
||||||
|
default:
|
||||||
|
return ServerFuncBtn.terminal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, ServerFuncBtn obj) {
|
||||||
|
switch (obj) {
|
||||||
|
case ServerFuncBtn.terminal:
|
||||||
|
writer.writeByte(0);
|
||||||
|
break;
|
||||||
|
case ServerFuncBtn.sftp:
|
||||||
|
writer.writeByte(1);
|
||||||
|
break;
|
||||||
|
case ServerFuncBtn.container:
|
||||||
|
writer.writeByte(2);
|
||||||
|
break;
|
||||||
|
case ServerFuncBtn.process:
|
||||||
|
writer.writeByte(3);
|
||||||
|
break;
|
||||||
|
case ServerFuncBtn.snippet:
|
||||||
|
writer.writeByte(5);
|
||||||
|
break;
|
||||||
|
case ServerFuncBtn.iperf:
|
||||||
|
writer.writeByte(6);
|
||||||
|
break;
|
||||||
|
case ServerFuncBtn.systemd:
|
||||||
|
writer.writeByte(8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is ServerFuncBtnAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
import 'package:server_box/data/model/server/server.dart';
|
import 'package:server_box/data/model/server/server.dart';
|
||||||
|
|
||||||
|
part 'net_view.g.dart';
|
||||||
|
|
||||||
|
@HiveType(typeId: 5)
|
||||||
enum NetViewType {
|
enum NetViewType {
|
||||||
|
@HiveField(0)
|
||||||
conn,
|
conn,
|
||||||
|
@HiveField(1)
|
||||||
speed,
|
speed,
|
||||||
|
@HiveField(2)
|
||||||
traffic;
|
traffic;
|
||||||
|
|
||||||
NetViewType get next => switch (this) {
|
NetViewType get next => switch (this) {
|
||||||
|
|||||||
51
lib/data/model/app/net_view.g.dart
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'net_view.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class NetViewTypeAdapter extends TypeAdapter<NetViewType> {
|
||||||
|
@override
|
||||||
|
final int typeId = 5;
|
||||||
|
|
||||||
|
@override
|
||||||
|
NetViewType read(BinaryReader reader) {
|
||||||
|
switch (reader.readByte()) {
|
||||||
|
case 0:
|
||||||
|
return NetViewType.conn;
|
||||||
|
case 1:
|
||||||
|
return NetViewType.speed;
|
||||||
|
case 2:
|
||||||
|
return NetViewType.traffic;
|
||||||
|
default:
|
||||||
|
return NetViewType.conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, NetViewType obj) {
|
||||||
|
switch (obj) {
|
||||||
|
case NetViewType.conn:
|
||||||
|
writer.writeByte(0);
|
||||||
|
break;
|
||||||
|
case NetViewType.speed:
|
||||||
|
writer.writeByte(1);
|
||||||
|
break;
|
||||||
|
case NetViewType.traffic:
|
||||||
|
writer.writeByte(2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is NetViewTypeAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
@@ -11,13 +11,13 @@ enum ServerDetailCards {
|
|||||||
swap(Icons.swap_horiz),
|
swap(Icons.swap_horiz),
|
||||||
gpu(Bootstrap.gpu_card),
|
gpu(Bootstrap.gpu_card),
|
||||||
disk(Bootstrap.device_hdd_fill),
|
disk(Bootstrap.device_hdd_fill),
|
||||||
smart(Icons.health_and_safety, sinceBuild: 1174),
|
|
||||||
net(ZondIcons.network),
|
net(ZondIcons.network),
|
||||||
sensor(MingCute.dashboard_4_line),
|
sensor(MingCute.dashboard_4_line),
|
||||||
temp(FontAwesome.temperature_empty_solid),
|
temp(FontAwesome.temperature_empty_solid),
|
||||||
battery(Icons.battery_full),
|
battery(Icons.battery_full),
|
||||||
pve(BoxIcons.bxs_dashboard, sinceBuild: 818),
|
pve(BoxIcons.bxs_dashboard, sinceBuild: 818),
|
||||||
custom(Icons.code, sinceBuild: 825);
|
custom(Icons.code, sinceBuild: 825),
|
||||||
|
;
|
||||||
|
|
||||||
final int? sinceBuild;
|
final int? sinceBuild;
|
||||||
|
|
||||||
@@ -31,20 +31,19 @@ enum ServerDetailCards {
|
|||||||
static final names = values.map((e) => e.name).toList();
|
static final names = values.map((e) => e.name).toList();
|
||||||
|
|
||||||
String get toStr => switch (this) {
|
String get toStr => switch (this) {
|
||||||
about => libL10n.about,
|
about => libL10n.about,
|
||||||
cpu => 'CPU',
|
cpu => 'CPU',
|
||||||
mem => 'RAM',
|
mem => 'RAM',
|
||||||
swap => 'Swap',
|
swap => 'Swap',
|
||||||
gpu => 'GPU',
|
gpu => 'GPU',
|
||||||
disk => l10n.disk,
|
disk => l10n.disk,
|
||||||
smart => l10n.diskHealth,
|
net => l10n.net,
|
||||||
net => l10n.net,
|
sensor => l10n.sensors,
|
||||||
sensor => l10n.sensors,
|
temp => l10n.temperature,
|
||||||
temp => l10n.temperature,
|
battery => l10n.battery,
|
||||||
battery => l10n.battery,
|
pve => 'PVE',
|
||||||
pve => 'PVE',
|
custom => l10n.cmd,
|
||||||
custom => l10n.cmd,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
/// If:
|
/// If:
|
||||||
/// Version 1 => user set [about], default is [about, cpu]
|
/// Version 1 => user set [about], default is [about, cpu]
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
import 'package:server_box/data/model/server/system.dart';
|
|
||||||
import 'package:server_box/data/provider/server.dart';
|
import 'package:server_box/data/provider/server.dart';
|
||||||
|
|
||||||
import 'package:server_box/data/res/build_data.dart';
|
import 'package:server_box/data/res/build_data.dart';
|
||||||
|
import 'package:server_box/data/model/server/system.dart';
|
||||||
|
|
||||||
enum ShellFunc {
|
enum ShellFunc {
|
||||||
status,
|
status,
|
||||||
@@ -9,7 +10,8 @@ enum ShellFunc {
|
|||||||
process,
|
process,
|
||||||
shutdown,
|
shutdown,
|
||||||
reboot,
|
reboot,
|
||||||
suspend;
|
suspend,
|
||||||
|
;
|
||||||
|
|
||||||
static const seperator = 'SrvBoxSep';
|
static const seperator = 'SrvBoxSep';
|
||||||
|
|
||||||
@@ -28,9 +30,8 @@ enum ShellFunc {
|
|||||||
/// Default is [scriptDirTmp]/[scriptFile], if this path is not accessible,
|
/// Default is [scriptDirTmp]/[scriptFile], if this path is not accessible,
|
||||||
/// it will be changed to [scriptDirHome]/[scriptFile].
|
/// it will be changed to [scriptDirHome]/[scriptFile].
|
||||||
static String getScriptDir(String id) {
|
static String getScriptDir(String id) {
|
||||||
final customScriptDir = ServerProvider.pick(
|
final customScriptDir =
|
||||||
id: id,
|
ServerProvider.pick(id: id)?.value.spi.custom?.scriptDir;
|
||||||
)?.value.spi.custom?.scriptDir;
|
|
||||||
if (customScriptDir != null) return customScriptDir;
|
if (customScriptDir != null) return customScriptDir;
|
||||||
return _scriptDirMap.putIfAbsent(id, () {
|
return _scriptDirMap.putIfAbsent(id, () {
|
||||||
return scriptDirTmp;
|
return scriptDirTmp;
|
||||||
@@ -38,10 +39,10 @@ enum ShellFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void switchScriptDir(String id) => switch (_scriptDirMap[id]) {
|
static void switchScriptDir(String id) => switch (_scriptDirMap[id]) {
|
||||||
scriptDirTmp => _scriptDirMap[id] = scriptDirHome,
|
scriptDirTmp => _scriptDirMap[id] = scriptDirHome,
|
||||||
scriptDirHome => _scriptDirMap[id] = scriptDirTmp,
|
scriptDirHome => _scriptDirMap[id] = scriptDirTmp,
|
||||||
_ => _scriptDirMap[id] = scriptDirHome,
|
_ => _scriptDirMap[id] = scriptDirHome,
|
||||||
};
|
};
|
||||||
|
|
||||||
static String getScriptPath(String id) {
|
static String getScriptPath(String id) {
|
||||||
return '${getScriptDir(id)}/$scriptFile';
|
return '${getScriptDir(id)}/$scriptFile';
|
||||||
@@ -58,13 +59,13 @@ chmod 755 $scriptPath
|
|||||||
}
|
}
|
||||||
|
|
||||||
String get flag => switch (this) {
|
String get flag => switch (this) {
|
||||||
ShellFunc.process => 'p',
|
ShellFunc.process => 'p',
|
||||||
ShellFunc.shutdown => 'sd',
|
ShellFunc.shutdown => 'sd',
|
||||||
ShellFunc.reboot => 'r',
|
ShellFunc.reboot => 'r',
|
||||||
ShellFunc.suspend => 'sp',
|
ShellFunc.suspend => 'sp',
|
||||||
ShellFunc.status => 's',
|
ShellFunc.status => 's',
|
||||||
// ShellFunc.docker=> 'd',
|
// ShellFunc.docker=> 'd',
|
||||||
};
|
};
|
||||||
|
|
||||||
String exec(String id) => 'sh ${getScriptPath(id)} -$flag';
|
String exec(String id) => 'sh ${getScriptPath(id)} -$flag';
|
||||||
|
|
||||||
@@ -95,14 +96,14 @@ if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
|||||||
else
|
else
|
||||||
\t${BSDStatusCmdType.values.map((e) => e.cmd).join(cmdDivider)}
|
\t${BSDStatusCmdType.values.map((e) => e.cmd).join(cmdDivider)}
|
||||||
fi''';
|
fi''';
|
||||||
// case ShellFunc.docker:
|
// case ShellFunc.docker:
|
||||||
// return '''
|
// return '''
|
||||||
// result=\$(docker version 2>&1 | grep "permission denied")
|
// result=\$(docker version 2>&1 | grep "permission denied")
|
||||||
// if [ "\$result" != "" ]; then
|
// if [ "\$result" != "" ]; then
|
||||||
// \t${_dockerCmds.join(_cmdDivider)}
|
// \t${_dockerCmds.join(_cmdDivider)}
|
||||||
// else
|
// else
|
||||||
// \t${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
|
// \t${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
|
||||||
// fi''';
|
// fi''';
|
||||||
case ShellFunc.process:
|
case ShellFunc.process:
|
||||||
return '''
|
return '''
|
||||||
if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
||||||
@@ -208,25 +209,22 @@ enum StatusCmdType {
|
|||||||
echo._('echo ${SystemType.linuxSign}'),
|
echo._('echo ${SystemType.linuxSign}'),
|
||||||
time._('date +%s'),
|
time._('date +%s'),
|
||||||
net._('cat /proc/net/dev'),
|
net._('cat /proc/net/dev'),
|
||||||
sys._('cat /etc/*-release | grep ^PRETTY_NAME'),
|
sys._('cat /etc/*-release | grep PRETTY_NAME'),
|
||||||
cpu._('cat /proc/stat | grep cpu'),
|
cpu._('cat /proc/stat | grep cpu'),
|
||||||
uptime._('uptime'),
|
uptime._('uptime'),
|
||||||
conn._('cat /proc/net/snmp'),
|
conn._('cat /proc/net/snmp'),
|
||||||
disk._(
|
disk._('df'),
|
||||||
'lsblk --bytes --json --output FSTYPE,PATH,NAME,KNAME,MOUNTPOINT,FSSIZE,FSUSED,FSAVAIL,FSUSE%,UUID',
|
|
||||||
),
|
|
||||||
mem._("cat /proc/meminfo | grep -E 'Mem|Swap'"),
|
mem._("cat /proc/meminfo | grep -E 'Mem|Swap'"),
|
||||||
tempType._('cat /sys/class/thermal/thermal_zone*/type'),
|
tempType._('cat /sys/class/thermal/thermal_zone*/type'),
|
||||||
tempVal._('cat /sys/class/thermal/thermal_zone*/temp'),
|
tempVal._('cat /sys/class/thermal/thermal_zone*/temp'),
|
||||||
host._('cat /etc/hostname'),
|
host._('cat /etc/hostname'),
|
||||||
diskio._('cat /proc/diskstats'),
|
diskio._('cat /proc/diskstats'),
|
||||||
battery._(
|
battery._(
|
||||||
'for f in /sys/class/power_supply/*/uevent; do cat "\$f"; echo; done',
|
'for f in /sys/class/power_supply/*/uevent; do cat "\$f"; echo; done'),
|
||||||
),
|
|
||||||
nvidia._('nvidia-smi -q -x'),
|
nvidia._('nvidia-smi -q -x'),
|
||||||
sensors._('sensors'),
|
sensors._('sensors'),
|
||||||
diskSmart._('for d in \$(lsblk -dn -o KNAME); do smartctl -a -j /dev/\$d; echo; done'),
|
cpuBrand._('cat /proc/cpuinfo | grep "model name"'),
|
||||||
cpuBrand._('cat /proc/cpuinfo | grep "model name"');
|
;
|
||||||
|
|
||||||
final String cmd;
|
final String cmd;
|
||||||
|
|
||||||
@@ -240,12 +238,12 @@ enum BSDStatusCmdType {
|
|||||||
sys._('uname -or'),
|
sys._('uname -or'),
|
||||||
cpu._('top -l 1 | grep "CPU usage"'),
|
cpu._('top -l 1 | grep "CPU usage"'),
|
||||||
uptime._('uptime'),
|
uptime._('uptime'),
|
||||||
// Keep df -k for BSD systems as lsblk is not available on macOS/BSD
|
|
||||||
disk._('df -k'),
|
disk._('df -k'),
|
||||||
mem._('top -l 1 | grep PhysMem'),
|
mem._('top -l 1 | grep PhysMem'),
|
||||||
//temp,
|
//temp,
|
||||||
host._('hostname'),
|
host._('hostname'),
|
||||||
cpuBrand._('sysctl -n machdep.cpu.brand_string');
|
cpuBrand._('sysctl -n machdep.cpu.brand_string'),
|
||||||
|
;
|
||||||
|
|
||||||
final String cmd;
|
final String cmd;
|
||||||
|
|
||||||
@@ -254,10 +252,10 @@ enum BSDStatusCmdType {
|
|||||||
|
|
||||||
extension StatusCmdTypeX on StatusCmdType {
|
extension StatusCmdTypeX on StatusCmdType {
|
||||||
String get i18n => switch (this) {
|
String get i18n => switch (this) {
|
||||||
StatusCmdType.sys => l10n.system,
|
StatusCmdType.sys => l10n.system,
|
||||||
StatusCmdType.host => l10n.host,
|
StatusCmdType.host => l10n.host,
|
||||||
StatusCmdType.uptime => l10n.uptime,
|
StatusCmdType.uptime => l10n.uptime,
|
||||||
StatusCmdType.battery => l10n.battery,
|
StatusCmdType.battery => l10n.battery,
|
||||||
final val => val.name,
|
final val => val.name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
24
lib/data/model/app/sync.dart
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
class SyncResult<T, E> {
|
||||||
|
final List<T> up;
|
||||||
|
final List<T> down;
|
||||||
|
final Map<T, E> err;
|
||||||
|
|
||||||
|
const SyncResult({
|
||||||
|
required this.up,
|
||||||
|
required this.down,
|
||||||
|
required this.err,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SyncResult{up: $up, down: $down, err: $err}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SyncIface<T> {
|
||||||
|
/// Merge [other] into [this], return [this] after merge.
|
||||||
|
/// Data in [other] has higher priority than [this].
|
||||||
|
FutureOr<void> sync(T other);
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:icons_plus/icons_plus.dart';
|
|
||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
import 'package:server_box/view/page/server/tab/tab.dart';
|
import 'package:server_box/view/page/server/tab.dart';
|
||||||
// import 'package:server_box/view/page/setting/entry.dart';
|
import 'package:server_box/view/page/setting/entry.dart';
|
||||||
import 'package:server_box/view/page/snippet/list.dart';
|
import 'package:server_box/view/page/snippet/list.dart';
|
||||||
import 'package:server_box/view/page/ssh/tab.dart';
|
import 'package:server_box/view/page/ssh/tab.dart';
|
||||||
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:server_box/view/page/storage/local.dart';
|
import 'package:server_box/view/page/storage/local.dart';
|
||||||
|
|
||||||
enum AppTab {
|
enum AppTab {
|
||||||
@@ -13,13 +13,13 @@ enum AppTab {
|
|||||||
ssh,
|
ssh,
|
||||||
file,
|
file,
|
||||||
snippet,
|
snippet,
|
||||||
//settings,
|
settings,
|
||||||
;
|
;
|
||||||
|
|
||||||
Widget get page {
|
Widget get page {
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
server => const ServerPage(),
|
server => const ServerPage(),
|
||||||
//settings => const SettingsPage(),
|
settings => const SettingsPage(),
|
||||||
ssh => const SSHTabPage(),
|
ssh => const SSHTabPage(),
|
||||||
file => const LocalFilePage(),
|
file => const LocalFilePage(),
|
||||||
snippet => const SnippetListPage(),
|
snippet => const SnippetListPage(),
|
||||||
@@ -33,11 +33,11 @@ enum AppTab {
|
|||||||
label: l10n.server,
|
label: l10n.server,
|
||||||
selectedIcon: const Icon(BoxIcons.bxs_server),
|
selectedIcon: const Icon(BoxIcons.bxs_server),
|
||||||
),
|
),
|
||||||
// settings => NavigationDestination(
|
settings => NavigationDestination(
|
||||||
// icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
// label: libL10n.setting,
|
label: libL10n.setting,
|
||||||
// selectedIcon: const Icon(Icons.settings),
|
selectedIcon: const Icon(Icons.settings),
|
||||||
// ),
|
),
|
||||||
ssh => const NavigationDestination(
|
ssh => const NavigationDestination(
|
||||||
icon: Icon(Icons.terminal_outlined),
|
icon: Icon(Icons.terminal_outlined),
|
||||||
label: 'SSH',
|
label: 'SSH',
|
||||||
@@ -56,41 +56,7 @@ enum AppTab {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationRailDestination get navRailDestination {
|
|
||||||
return switch (this) {
|
|
||||||
server => NavigationRailDestination(
|
|
||||||
icon: const Icon(BoxIcons.bx_server),
|
|
||||||
label: Text(l10n.server),
|
|
||||||
selectedIcon: const Icon(BoxIcons.bxs_server),
|
|
||||||
),
|
|
||||||
// settings => NavigationRailDestination(
|
|
||||||
// icon: const Icon(Icons.settings),
|
|
||||||
// label: libL10n.setting,
|
|
||||||
// selectedIcon: const Icon(Icons.settings),
|
|
||||||
// ),
|
|
||||||
ssh => const NavigationRailDestination(
|
|
||||||
icon: Icon(Icons.terminal_outlined),
|
|
||||||
label: Text('SSH'),
|
|
||||||
selectedIcon: Icon(Icons.terminal),
|
|
||||||
),
|
|
||||||
snippet => NavigationRailDestination(
|
|
||||||
icon: const Icon(Icons.code),
|
|
||||||
label: Text(l10n.snippet),
|
|
||||||
selectedIcon: const Icon(Icons.code),
|
|
||||||
),
|
|
||||||
file => NavigationRailDestination(
|
|
||||||
icon: const Icon(Icons.folder_open),
|
|
||||||
label: Text(libL10n.file),
|
|
||||||
selectedIcon: const Icon(Icons.folder),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<NavigationDestination> get navDestinations {
|
static List<NavigationDestination> get navDestinations {
|
||||||
return AppTab.values.map((e) => e.navDestination).toList();
|
return AppTab.values.map((e) => e.navDestination).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<NavigationRailDestination> get navRailDestinations {
|
|
||||||
return AppTab.values.map((e) => e.navRailDestination).toList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ enum PkgManager {
|
|||||||
return 'opkg list-upgradable';
|
return 'opkg list-upgradable';
|
||||||
case PkgManager.apk:
|
case PkgManager.apk:
|
||||||
return 'apk list --upgradable';
|
return 'apk list --upgradable';
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +56,8 @@ enum PkgManager {
|
|||||||
return 'opkg upgrade $args';
|
return 'opkg upgrade $args';
|
||||||
case PkgManager.apk:
|
case PkgManager.apk:
|
||||||
return 'apk upgrade';
|
return 'apk upgrade';
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +109,6 @@ enum PkgManager {
|
|||||||
return PkgManager.apt;
|
return PkgManager.apt;
|
||||||
case Dist.opensuse:
|
case Dist.opensuse:
|
||||||
return PkgManager.zypper;
|
return PkgManager.zypper;
|
||||||
case Dist.coreelec:
|
|
||||||
case Dist.wrt:
|
case Dist.wrt:
|
||||||
return PkgManager.opkg;
|
return PkgManager.opkg;
|
||||||
case Dist.arch:
|
case Dist.arch:
|
||||||
|
|||||||
@@ -1,27 +1,32 @@
|
|||||||
|
import 'package:hive_flutter/adapters.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
part 'custom.g.dart';
|
part 'custom.g.dart';
|
||||||
|
|
||||||
@JsonSerializable(includeIfNull: false)
|
@JsonSerializable()
|
||||||
|
@HiveType(typeId: 7)
|
||||||
final class ServerCustom {
|
final class ServerCustom {
|
||||||
// @HiveField(0)
|
// @HiveField(0)
|
||||||
// final String? temperature;
|
// final String? temperature;
|
||||||
|
@HiveField(1)
|
||||||
final String? pveAddr;
|
final String? pveAddr;
|
||||||
|
@HiveField(2, defaultValue: false)
|
||||||
final bool pveIgnoreCert;
|
final bool pveIgnoreCert;
|
||||||
|
|
||||||
/// {"title": "cmd"}
|
/// {"title": "cmd"}
|
||||||
|
@HiveField(3)
|
||||||
final Map<String, String>? cmds;
|
final Map<String, String>? cmds;
|
||||||
|
@HiveField(4)
|
||||||
final String? preferTempDev;
|
final String? preferTempDev;
|
||||||
|
@HiveField(5)
|
||||||
final String? logoUrl;
|
final String? logoUrl;
|
||||||
|
|
||||||
/// The device name of the network interface displayed in the home server card.
|
/// The device name of the network interface displayed in the home server card.
|
||||||
|
@HiveField(6)
|
||||||
final String? netDev;
|
final String? netDev;
|
||||||
|
|
||||||
/// The directory where the script is stored.
|
/// The directory where the script is stored.
|
||||||
|
@HiveField(7)
|
||||||
final String? scriptDir;
|
final String? scriptDir;
|
||||||
|
|
||||||
const ServerCustom({
|
const ServerCustom({
|
||||||
@@ -35,7 +40,8 @@ final class ServerCustom {
|
|||||||
this.scriptDir,
|
this.scriptDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ServerCustom.fromJson(Map<String, dynamic> json) => _$ServerCustomFromJson(json);
|
factory ServerCustom.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$ServerCustomFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$ServerCustomToJson(this);
|
Map<String, dynamic> toJson() => _$ServerCustomToJson(this);
|
||||||
|
|
||||||
|
|||||||
@@ -2,29 +2,85 @@
|
|||||||
|
|
||||||
part of 'custom.dart';
|
part of 'custom.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class ServerCustomAdapter extends TypeAdapter<ServerCustom> {
|
||||||
|
@override
|
||||||
|
final int typeId = 7;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ServerCustom read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return ServerCustom(
|
||||||
|
pveAddr: fields[1] as String?,
|
||||||
|
pveIgnoreCert: fields[2] == null ? false : fields[2] as bool,
|
||||||
|
cmds: (fields[3] as Map?)?.cast<String, String>(),
|
||||||
|
preferTempDev: fields[4] as String?,
|
||||||
|
logoUrl: fields[5] as String?,
|
||||||
|
netDev: fields[6] as String?,
|
||||||
|
scriptDir: fields[7] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, ServerCustom obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(7)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.pveAddr)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.pveIgnoreCert)
|
||||||
|
..writeByte(3)
|
||||||
|
..write(obj.cmds)
|
||||||
|
..writeByte(4)
|
||||||
|
..write(obj.preferTempDev)
|
||||||
|
..writeByte(5)
|
||||||
|
..write(obj.logoUrl)
|
||||||
|
..writeByte(6)
|
||||||
|
..write(obj.netDev)
|
||||||
|
..writeByte(7)
|
||||||
|
..write(obj.scriptDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is ServerCustomAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
ServerCustom _$ServerCustomFromJson(Map<String, dynamic> json) => ServerCustom(
|
ServerCustom _$ServerCustomFromJson(Map<String, dynamic> json) => ServerCustom(
|
||||||
pveAddr: json['pveAddr'] as String?,
|
pveAddr: json['pveAddr'] as String?,
|
||||||
pveIgnoreCert: json['pveIgnoreCert'] as bool? ?? false,
|
pveIgnoreCert: json['pveIgnoreCert'] as bool? ?? false,
|
||||||
cmds: (json['cmds'] as Map<String, dynamic>?)?.map(
|
cmds: (json['cmds'] as Map<String, dynamic>?)?.map(
|
||||||
(k, e) => MapEntry(k, e as String),
|
(k, e) => MapEntry(k, e as String),
|
||||||
),
|
),
|
||||||
preferTempDev: json['preferTempDev'] as String?,
|
preferTempDev: json['preferTempDev'] as String?,
|
||||||
logoUrl: json['logoUrl'] as String?,
|
logoUrl: json['logoUrl'] as String?,
|
||||||
netDev: json['netDev'] as String?,
|
netDev: json['netDev'] as String?,
|
||||||
scriptDir: json['scriptDir'] as String?,
|
scriptDir: json['scriptDir'] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$ServerCustomToJson(ServerCustom instance) =>
|
Map<String, dynamic> _$ServerCustomToJson(ServerCustom instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
if (instance.pveAddr case final value?) 'pveAddr': value,
|
'pveAddr': instance.pveAddr,
|
||||||
'pveIgnoreCert': instance.pveIgnoreCert,
|
'pveIgnoreCert': instance.pveIgnoreCert,
|
||||||
if (instance.cmds case final value?) 'cmds': value,
|
'cmds': instance.cmds,
|
||||||
if (instance.preferTempDev case final value?) 'preferTempDev': value,
|
'preferTempDev': instance.preferTempDev,
|
||||||
if (instance.logoUrl case final value?) 'logoUrl': value,
|
'logoUrl': instance.logoUrl,
|
||||||
if (instance.netDev case final value?) 'netDev': value,
|
'netDev': instance.netDev,
|
||||||
if (instance.scriptDir case final value?) 'scriptDir': value,
|
'scriptDir': instance.scriptDir,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,208 +1,29 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:server_box/data/model/server/time_seq.dart';
|
import 'package:server_box/data/model/server/time_seq.dart';
|
||||||
|
|
||||||
import 'package:server_box/data/res/misc.dart';
|
import 'package:server_box/data/res/misc.dart';
|
||||||
|
|
||||||
class Disk with EquatableMixin {
|
class Disk {
|
||||||
final String path;
|
final String fs;
|
||||||
final String? fsTyp;
|
|
||||||
final String mount;
|
final String mount;
|
||||||
final int usedPercent;
|
final int usedPercent;
|
||||||
final BigInt used;
|
final BigInt used;
|
||||||
final BigInt size;
|
final BigInt size;
|
||||||
final BigInt avail;
|
final BigInt avail;
|
||||||
|
|
||||||
/// Device name (e.g., sda1, nvme0n1p1)
|
|
||||||
final String? name;
|
|
||||||
|
|
||||||
/// Internal kernel device name
|
|
||||||
final String? kname;
|
|
||||||
|
|
||||||
/// Filesystem UUID
|
|
||||||
final String? uuid;
|
|
||||||
|
|
||||||
/// Child disks (partitions)
|
|
||||||
final List<Disk> children;
|
|
||||||
|
|
||||||
const Disk({
|
const Disk({
|
||||||
required this.path,
|
required this.fs,
|
||||||
this.fsTyp,
|
|
||||||
required this.mount,
|
required this.mount,
|
||||||
required this.usedPercent,
|
required this.usedPercent,
|
||||||
required this.used,
|
required this.used,
|
||||||
required this.size,
|
required this.size,
|
||||||
required this.avail,
|
required this.avail,
|
||||||
this.name,
|
|
||||||
this.kname,
|
|
||||||
this.uuid,
|
|
||||||
this.children = const [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
static List<Disk> parse(String raw) {
|
static List<Disk> parse(String raw) {
|
||||||
final list = <Disk>[];
|
|
||||||
raw = raw.trim();
|
|
||||||
try {
|
|
||||||
if (raw.startsWith('{')) {
|
|
||||||
// Parse JSON output from lsblk command
|
|
||||||
final Map<String, dynamic> jsonData = json.decode(raw);
|
|
||||||
final List<dynamic> blockdevices = jsonData['blockdevices'] ?? [];
|
|
||||||
|
|
||||||
for (final device in blockdevices) {
|
|
||||||
// Process each device
|
|
||||||
_processTopLevelDevice(device, list);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Fallback to the old parsing method in case of non-JSON output
|
|
||||||
return _parseWithOldMethod(raw);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Loggers.app.warning('Failed to parse disk info: $e', e);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process a top-level device and add all valid disks to the list
|
|
||||||
static void _processTopLevelDevice(Map<String, dynamic> device, List<Disk> list) {
|
|
||||||
final disk = _processDiskDevice(device);
|
|
||||||
if (disk != null) {
|
|
||||||
list.add(disk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For devices with children (like physical disks with partitions),
|
|
||||||
// also process each child individually to ensure BTRFS RAID disks are properly handled
|
|
||||||
final List<dynamic> childDevices = device['children'] ?? [];
|
|
||||||
for (final childDevice in childDevices) {
|
|
||||||
final String childPath = childDevice['path']?.toString() ?? '';
|
|
||||||
final String childFsType = childDevice['fstype']?.toString() ?? '';
|
|
||||||
|
|
||||||
// If this is a BTRFS partition, add it directly to ensure it's properly represented
|
|
||||||
if (childFsType == 'btrfs' && childPath.isNotEmpty) {
|
|
||||||
final childDisk = _processSingleDevice(childDevice);
|
|
||||||
if (childDisk != null) {
|
|
||||||
list.add(childDisk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process a single device without recursively processing its children
|
|
||||||
static Disk? _processSingleDevice(Map<String, dynamic> device) {
|
|
||||||
final fstype = device['fstype']?.toString();
|
|
||||||
final String mountpoint = device['mountpoint']?.toString() ?? '';
|
|
||||||
final String path = device['path']?.toString() ?? '';
|
|
||||||
|
|
||||||
if (path.isEmpty || (fstype == null && mountpoint.isEmpty)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_shouldCalc(fstype ?? '', mountpoint)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final sizeStr = device['fssize']?.toString() ?? '0';
|
|
||||||
final size = (BigInt.tryParse(sizeStr) ?? BigInt.zero) ~/ BigInt.from(1024);
|
|
||||||
|
|
||||||
final usedStr = device['fsused']?.toString() ?? '0';
|
|
||||||
final used = (BigInt.tryParse(usedStr) ?? BigInt.zero) ~/ BigInt.from(1024);
|
|
||||||
|
|
||||||
final availStr = device['fsavail']?.toString() ?? '0';
|
|
||||||
final avail = (BigInt.tryParse(availStr) ?? BigInt.zero) ~/ BigInt.from(1024);
|
|
||||||
|
|
||||||
// Parse fsuse% which is usually in the format "45%"
|
|
||||||
String usePercentStr = device['fsuse%']?.toString() ?? '0';
|
|
||||||
usePercentStr = usePercentStr.replaceAll('%', '');
|
|
||||||
final usedPercent = int.tryParse(usePercentStr) ?? 0;
|
|
||||||
|
|
||||||
final name = device['name']?.toString();
|
|
||||||
final kname = device['kname']?.toString();
|
|
||||||
final uuid = device['uuid']?.toString();
|
|
||||||
|
|
||||||
return Disk(
|
|
||||||
path: path,
|
|
||||||
fsTyp: fstype,
|
|
||||||
mount: mountpoint,
|
|
||||||
usedPercent: usedPercent,
|
|
||||||
used: used,
|
|
||||||
size: size,
|
|
||||||
avail: avail,
|
|
||||||
name: name,
|
|
||||||
kname: kname,
|
|
||||||
uuid: uuid,
|
|
||||||
children: const [], // No children for direct device
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Disk? _processDiskDevice(Map<String, dynamic> device) {
|
|
||||||
final fstype = device['fstype']?.toString();
|
|
||||||
final String mountpoint = device['mountpoint']?.toString() ?? '';
|
|
||||||
|
|
||||||
// For parent devices that don't have a mountpoint themselves
|
|
||||||
final String path = device['path']?.toString() ?? '';
|
|
||||||
final String mount = mountpoint;
|
|
||||||
final List<Disk> childDisks = [];
|
|
||||||
|
|
||||||
// Process children devices recursively
|
|
||||||
final List<dynamic> childDevices = device['children'] ?? [];
|
|
||||||
for (final childDevice in childDevices) {
|
|
||||||
final childDisk = _processDiskDevice(childDevice);
|
|
||||||
if (childDisk != null) {
|
|
||||||
childDisks.add(childDisk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle common filesystem cases or parent devices with children
|
|
||||||
if ((fstype != null && _shouldCalc(fstype, mount)) ||
|
|
||||||
(childDisks.isNotEmpty && path.isNotEmpty)) {
|
|
||||||
final sizeStr = device['fssize']?.toString() ?? '0';
|
|
||||||
final size = (BigInt.tryParse(sizeStr) ?? BigInt.zero) ~/ BigInt.from(1024);
|
|
||||||
|
|
||||||
final usedStr = device['fsused']?.toString() ?? '0';
|
|
||||||
final used = (BigInt.tryParse(usedStr) ?? BigInt.zero) ~/ BigInt.from(1024);
|
|
||||||
|
|
||||||
final availStr = device['fsavail']?.toString() ?? '0';
|
|
||||||
final avail = (BigInt.tryParse(availStr) ?? BigInt.zero) ~/ BigInt.from(1024);
|
|
||||||
|
|
||||||
// Parse fsuse% which is usually in the format "45%"
|
|
||||||
String usePercentStr = device['fsuse%']?.toString() ?? '0';
|
|
||||||
usePercentStr = usePercentStr.replaceAll('%', '');
|
|
||||||
final usedPercent = int.tryParse(usePercentStr) ?? 0;
|
|
||||||
|
|
||||||
final name = device['name']?.toString();
|
|
||||||
final kname = device['kname']?.toString();
|
|
||||||
final uuid = device['uuid']?.toString();
|
|
||||||
|
|
||||||
return Disk(
|
|
||||||
path: path,
|
|
||||||
fsTyp: fstype,
|
|
||||||
mount: mount,
|
|
||||||
usedPercent: usedPercent,
|
|
||||||
used: used,
|
|
||||||
size: size,
|
|
||||||
avail: avail,
|
|
||||||
name: name,
|
|
||||||
kname: kname,
|
|
||||||
uuid: uuid,
|
|
||||||
children: childDisks,
|
|
||||||
);
|
|
||||||
} else if (childDisks.isNotEmpty) {
|
|
||||||
// If this is a parent device with no filesystem but has children,
|
|
||||||
// return the first valid child instead
|
|
||||||
if (childDisks.isNotEmpty) {
|
|
||||||
return childDisks.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to the old parsing method in case JSON parsing fails
|
|
||||||
static List<Disk> _parseWithOldMethod(String raw) {
|
|
||||||
final list = <Disk>[];
|
final list = <Disk>[];
|
||||||
final items = raw.split('\n');
|
final items = raw.split('\n');
|
||||||
if (items.isNotEmpty) items.removeAt(0);
|
items.removeAt(0);
|
||||||
var pathCache = '';
|
var pathCache = '';
|
||||||
for (var item in items) {
|
for (var item in items) {
|
||||||
if (item.isEmpty) {
|
if (item.isEmpty) {
|
||||||
@@ -222,12 +43,12 @@ class Disk with EquatableMixin {
|
|||||||
final mount = vals[5];
|
final mount = vals[5];
|
||||||
if (!_shouldCalc(fs, mount)) continue;
|
if (!_shouldCalc(fs, mount)) continue;
|
||||||
list.add(Disk(
|
list.add(Disk(
|
||||||
path: fs,
|
fs: fs,
|
||||||
mount: mount,
|
mount: mount,
|
||||||
usedPercent: int.parse(vals[4].replaceFirst('%', '')),
|
usedPercent: int.parse(vals[4].replaceFirst('%', '')),
|
||||||
used: BigInt.parse(vals[2]) ~/ BigInt.from(1024),
|
used: BigInt.parse(vals[2]),
|
||||||
size: BigInt.parse(vals[1]) ~/ BigInt.from(1024),
|
size: BigInt.parse(vals[1]),
|
||||||
avail: BigInt.parse(vals[3]) ~/ BigInt.from(1024),
|
avail: BigInt.parse(vals[3]),
|
||||||
));
|
));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
continue;
|
continue;
|
||||||
@@ -237,8 +58,9 @@ class Disk with EquatableMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props =>
|
String toString() {
|
||||||
[path, name, kname, fsTyp, mount, usedPercent, used, size, avail, uuid, children];
|
return 'Disk{dev: $fs, mount: $mount, usedPercent: $usedPercent, used: $used, size: $size, avail: $avail}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiskIO extends TimeSeq<List<DiskIOPiece>> {
|
class DiskIO extends TimeSeq<List<DiskIOPiece>> {
|
||||||
@@ -250,16 +72,9 @@ class DiskIO extends TimeSeq<List<DiskIOPiece>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(double?, double?) _getSpeed(String dev) {
|
(double?, double?) _getSpeed(String dev) {
|
||||||
// Extract the device name from path if needed
|
if (dev.startsWith('/dev/')) dev = dev.substring(5);
|
||||||
String searchDev = dev;
|
final old = pre.firstWhereOrNull((e) => e.dev == dev);
|
||||||
if (dev.startsWith('/dev/')) {
|
final new_ = now.firstWhereOrNull((e) => e.dev == dev);
|
||||||
searchDev = dev.substring(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find by exact device name first
|
|
||||||
final old = pre.firstWhereOrNull((e) => e.dev == searchDev);
|
|
||||||
final new_ = now.firstWhereOrNull((e) => e.dev == searchDev);
|
|
||||||
|
|
||||||
if (old == null || new_ == null) return (null, null);
|
if (old == null || new_ == null) return (null, null);
|
||||||
final sectorsRead = new_.sectorsRead - old.sectorsRead;
|
final sectorsRead = new_.sectorsRead - old.sectorsRead;
|
||||||
final sectorsWrite = new_.sectorsWrite - old.sectorsWrite;
|
final sectorsWrite = new_.sectorsWrite - old.sectorsWrite;
|
||||||
@@ -289,14 +104,11 @@ class DiskIO extends TimeSeq<List<DiskIOPiece>> {
|
|||||||
!item.dev.startsWith('vd') &&
|
!item.dev.startsWith('vd') &&
|
||||||
!item.dev.startsWith('hd') &&
|
!item.dev.startsWith('hd') &&
|
||||||
!item.dev.startsWith('mmcblk') &&
|
!item.dev.startsWith('mmcblk') &&
|
||||||
!item.dev.startsWith('sr')) {
|
!item.dev.startsWith('sr')) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final (read_, write_) = _getSpeed(item.dev);
|
final (read_, write_) = _getSpeed(item.dev);
|
||||||
read += read_ ?? 0;
|
read += read_ ?? 0;
|
||||||
write += write_ ?? 0;
|
write += write_ ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
final readStr = '${read.bytes2Str}/s';
|
final readStr = '${read.bytes2Str}/s';
|
||||||
final writeStr = '${write.bytes2Str}/s';
|
final writeStr = '${write.bytes2Str}/s';
|
||||||
return (readStr, writeStr);
|
return (readStr, writeStr);
|
||||||
@@ -354,11 +166,7 @@ class DiskUsage {
|
|||||||
required this.size,
|
required this.size,
|
||||||
});
|
});
|
||||||
|
|
||||||
double get usedPercent {
|
double get usedPercent => used / size * 100;
|
||||||
// Avoid division by zero
|
|
||||||
if (size == BigInt.zero) return 0;
|
|
||||||
return used / size * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find all devs, add their used and size
|
/// Find all devs, add their used and size
|
||||||
static DiskUsage parse(List<Disk> disks) {
|
static DiskUsage parse(List<Disk> disks) {
|
||||||
@@ -366,12 +174,9 @@ class DiskUsage {
|
|||||||
var used = BigInt.zero;
|
var used = BigInt.zero;
|
||||||
var size = BigInt.zero;
|
var size = BigInt.zero;
|
||||||
for (var disk in disks) {
|
for (var disk in disks) {
|
||||||
if (!_shouldCalc(disk.path, disk.mount)) continue;
|
if (!_shouldCalc(disk.fs, disk.mount)) continue;
|
||||||
// Use a combination of path and kernel name to uniquely identify disks
|
if (devs.contains(disk.fs)) continue;
|
||||||
// This helps distinguish between multiple physical disks in BTRFS RAID setups
|
devs.add(disk.fs);
|
||||||
final uniqueId = '${disk.path}:${disk.kname ?? "unknown"}';
|
|
||||||
if (devs.contains(uniqueId)) continue;
|
|
||||||
devs.add(uniqueId);
|
|
||||||
used += disk.used;
|
used += disk.used;
|
||||||
size += disk.size;
|
size += disk.size;
|
||||||
}
|
}
|
||||||
@@ -380,24 +185,12 @@ class DiskUsage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool _shouldCalc(String fs, String mount) {
|
bool _shouldCalc(String fs, String mount) {
|
||||||
// Skip swap partitions
|
|
||||||
// if (mount == '[SWAP]') return false;
|
|
||||||
|
|
||||||
// Include standard filesystems
|
|
||||||
if (fs.startsWith('/dev')) return true;
|
if (fs.startsWith('/dev')) return true;
|
||||||
// Some NAS may have mounted path like this `//192.168.1.2/`
|
// Some NAS may have mounted path like this `//192.168.1.2/`
|
||||||
if (fs.startsWith('//')) return true;
|
if (fs.startsWith('//')) return true;
|
||||||
if (mount.startsWith('/mnt')) return true;
|
if (mount.startsWith('/mnt')) return true;
|
||||||
|
// if (fs.startsWith('shm') ||
|
||||||
// Include common filesystem types
|
// fs.startsWith('overlay') ||
|
||||||
// final commonFsTypes = ['ext2', 'ext3', 'ext4', 'xfs', 'btrfs', 'zfs', 'ntfs', 'fat', 'vfat'];
|
// fs.startsWith('tmpfs')) return false;
|
||||||
// if (commonFsTypes.any((type) => fs.toLowerCase() == type)) return true;
|
return false;
|
||||||
|
|
||||||
// Skip special filesystems
|
|
||||||
// if (fs == 'LVM2_member' || fs == 'crypto_LUKS') return false;
|
|
||||||
if (fs.startsWith('shm') || fs.startsWith('overlay') || fs.startsWith('tmpfs')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,293 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
|
|
||||||
part 'disk_smart.freezed.dart';
|
|
||||||
part 'disk_smart.g.dart';
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class DiskSmart with _$DiskSmart {
|
|
||||||
const DiskSmart._();
|
|
||||||
|
|
||||||
const factory DiskSmart({
|
|
||||||
required String device,
|
|
||||||
bool? healthy,
|
|
||||||
double? temperature,
|
|
||||||
String? model,
|
|
||||||
String? serial,
|
|
||||||
int? powerOnHours,
|
|
||||||
int? powerCycleCount,
|
|
||||||
required Map<String, dynamic> rawData,
|
|
||||||
required Map<String, SmartAttribute> smartAttributes,
|
|
||||||
}) = _DiskSmart;
|
|
||||||
|
|
||||||
factory DiskSmart.fromJson(Map<String, dynamic> json) => _$DiskSmartFromJson(json);
|
|
||||||
|
|
||||||
static List<DiskSmart> parse(String raw) {
|
|
||||||
final results = <DiskSmart>[];
|
|
||||||
|
|
||||||
final jsonBlocks = raw.split('\n\n').where((s) => s.trim().isNotEmpty);
|
|
||||||
|
|
||||||
for (final jsonStr in jsonBlocks) {
|
|
||||||
try {
|
|
||||||
final data = json.decode(jsonStr.trim()) as Map<String, dynamic>;
|
|
||||||
|
|
||||||
// Basic
|
|
||||||
final device = data['device']?['name']?.toString() ?? '';
|
|
||||||
|
|
||||||
if (!_isPhysicalDisk(device)) continue;
|
|
||||||
|
|
||||||
final healthy = _parseHealthStatus(data);
|
|
||||||
|
|
||||||
// Model and Serial
|
|
||||||
final model =
|
|
||||||
data['model_name']?.toString() ??
|
|
||||||
data['model_family']?.toString() ??
|
|
||||||
data['device']?['model_name']?.toString();
|
|
||||||
final serial = data['serial_number']?.toString() ?? data['device']?['serial_number']?.toString();
|
|
||||||
|
|
||||||
// SMART Attrs
|
|
||||||
final smartAttributes = _parseSmartAttributes(data);
|
|
||||||
final temperature = _extractTemperature(data, smartAttributes);
|
|
||||||
final powerOnHours =
|
|
||||||
data['power_on_time']?['hours'] as int? ?? smartAttributes['Power_On_Hours']?.rawValue as int?;
|
|
||||||
final powerCycleCount =
|
|
||||||
data['power_cycle_count'] as int? ?? smartAttributes['Power_Cycle_Count']?.rawValue as int?;
|
|
||||||
|
|
||||||
results.add(
|
|
||||||
DiskSmart(
|
|
||||||
device: device,
|
|
||||||
healthy: healthy,
|
|
||||||
temperature: temperature,
|
|
||||||
model: model,
|
|
||||||
serial: serial,
|
|
||||||
powerOnHours: powerOnHours,
|
|
||||||
powerCycleCount: powerCycleCount,
|
|
||||||
rawData: data,
|
|
||||||
smartAttributes: smartAttributes,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (e, s) {
|
|
||||||
Loggers.app.warning('DiskSmart parse', e, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _isPhysicalDisk(String device) {
|
|
||||||
if (device.isEmpty) return false;
|
|
||||||
|
|
||||||
// Common patterns for physical disks
|
|
||||||
final patterns = [
|
|
||||||
RegExp(r'^/dev/sd[a-z]$'), // SATA/SCSI: /dev/sda, /dev/sdb
|
|
||||||
RegExp(r'^/dev/hd[a-z]$'), // IDE: /dev/hda, /dev/hdb
|
|
||||||
RegExp(r'^/dev/nvme\d+n\d+$'), // NVMe: /dev/nvme0n1, /dev/nvme1n1
|
|
||||||
RegExp(r'^/dev/mmcblk\d+$'), // MMC: /dev/mmcblk0
|
|
||||||
RegExp(r'^/dev/vd[a-z]$'), // VirtIO: /dev/vda, /dev/vdb
|
|
||||||
RegExp(r'^/dev/xvd[a-z]$'), // Xen: /dev/xvda, /dev/xvdb
|
|
||||||
];
|
|
||||||
|
|
||||||
return patterns.any((pattern) => pattern.hasMatch(device));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool? _parseHealthStatus(Map<String, dynamic> data) {
|
|
||||||
// smart_status.passed
|
|
||||||
final smartStatus = data['smart_status'];
|
|
||||||
if (smartStatus is Map<String, dynamic>) {
|
|
||||||
final passed = smartStatus['passed'];
|
|
||||||
if (passed is bool) return passed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// smart_status.status
|
|
||||||
if (smartStatus is Map<String, dynamic>) {
|
|
||||||
final status = smartStatus['status']?.toString().toLowerCase();
|
|
||||||
if (status != null) {
|
|
||||||
if (status.contains('pass') || status.contains('ok')) return true;
|
|
||||||
if (status.contains('fail')) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// smart_status
|
|
||||||
final rootSmartStatus = data['smart_status']?.toString().toLowerCase();
|
|
||||||
if (rootSmartStatus != null) {
|
|
||||||
if (rootSmartStatus.contains('pass') || rootSmartStatus.contains('ok')) return true;
|
|
||||||
if (rootSmartStatus.contains('fail')) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// health attrs
|
|
||||||
final attrTable = data['ata_smart_attributes']?['table'] as List?;
|
|
||||||
if (attrTable != null) {
|
|
||||||
var hasFailingAttributes = false;
|
|
||||||
|
|
||||||
for (final attr in attrTable) {
|
|
||||||
if (attr is Map<String, dynamic>) {
|
|
||||||
final whenFailed = attr['when_failed']?.toString();
|
|
||||||
if (whenFailed != null && whenFailed.isNotEmpty && whenFailed != 'never') {
|
|
||||||
hasFailingAttributes = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether the attribute is critical
|
|
||||||
final name = attr['name']?.toString();
|
|
||||||
final value = attr['value'] as int?;
|
|
||||||
final thresh = attr['thresh'] as int?;
|
|
||||||
|
|
||||||
if (name != null && value != null && thresh != null && thresh > 0) {
|
|
||||||
const criticalAttrs = [
|
|
||||||
'Reallocated_Sector_Ct',
|
|
||||||
'Reallocated_Event_Count',
|
|
||||||
'Current_Pending_Sector',
|
|
||||||
'Offline_Uncorrectable',
|
|
||||||
'UDMA_CRC_Error_Count',
|
|
||||||
];
|
|
||||||
|
|
||||||
if (criticalAttrs.contains(name) && value < thresh) {
|
|
||||||
hasFailingAttributes = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasFailingAttributes) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attrTable != null && attrTable.isNotEmpty) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uncertain status, assume healthy
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<String, SmartAttribute> _parseSmartAttributes(Map<String, dynamic> data) {
|
|
||||||
final attributes = <String, SmartAttribute>{};
|
|
||||||
|
|
||||||
final attrTable = data['ata_smart_attributes']?['table'] as List?;
|
|
||||||
if (attrTable == null) return attributes;
|
|
||||||
|
|
||||||
for (final attr in attrTable) {
|
|
||||||
if (attr is Map<String, dynamic>) {
|
|
||||||
final name = attr['name']?.toString();
|
|
||||||
if (name != null) {
|
|
||||||
attributes[name] = SmartAttribute(
|
|
||||||
id: attr['id'] as int?,
|
|
||||||
name: name,
|
|
||||||
value: attr['value'] as int?,
|
|
||||||
worst: attr['worst'] as int?,
|
|
||||||
thresh: attr['thresh'] as int?,
|
|
||||||
whenFailed: attr['when_failed']?.toString(),
|
|
||||||
rawValue: attr['raw']?['value'],
|
|
||||||
rawString: attr['raw']?['string']?.toString(),
|
|
||||||
flags: SmartAttributeFlags.fromMap(attr['flags'] as Map<String, dynamic>? ?? {}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final _tempReg = RegExp(r'^(\d+(?:\.\d+)?)');
|
|
||||||
|
|
||||||
/// Extract temperature from the data
|
|
||||||
static double? _extractTemperature(Map<String, dynamic> data, Map<String, SmartAttribute> attrs) {
|
|
||||||
// Directly
|
|
||||||
final directTemp = data['temperature']?['current'];
|
|
||||||
if (directTemp is num) return directTemp.toDouble();
|
|
||||||
|
|
||||||
// SMART attribute
|
|
||||||
final tempAttr = attrs['Temperature_Celsius'];
|
|
||||||
if (tempAttr != null) {
|
|
||||||
// "35 (Min/Max 14/61)"
|
|
||||||
final rawString = tempAttr.rawString;
|
|
||||||
if (rawString != null) {
|
|
||||||
final match = _tempReg.firstMatch(rawString);
|
|
||||||
if (match != null) {
|
|
||||||
return double.tryParse(match.group(1)!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple numeric value
|
|
||||||
if (tempAttr.rawValue is num && tempAttr.rawValue! < 150) {
|
|
||||||
return tempAttr.rawValue!.toDouble();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the specific SMART attribute by name
|
|
||||||
SmartAttribute? getAttribute(String name) => smartAttributes[name];
|
|
||||||
|
|
||||||
int? get ssdLifeLeft => smartAttributes['SSD_Life_Left']?.rawValue as int?;
|
|
||||||
int? get lifetimeWritesGiB => smartAttributes['Lifetime_Writes_GiB']?.rawValue as int?;
|
|
||||||
int? get lifetimeReadsGiB => smartAttributes['Lifetime_Reads_GiB']?.rawValue as int?;
|
|
||||||
int? get unsafeShutdownCount => smartAttributes['Unsafe_Shutdown_Count']?.rawValue as int?;
|
|
||||||
int? get averageEraseCount => smartAttributes['Average_Erase_Count']?.rawValue as int?;
|
|
||||||
int? get maxEraseCount => smartAttributes['Max_Erase_Count']?.rawValue as int?;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => 'DiskSmart($device)';
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class SmartAttribute with _$SmartAttribute {
|
|
||||||
const SmartAttribute._();
|
|
||||||
|
|
||||||
const factory SmartAttribute({
|
|
||||||
int? id,
|
|
||||||
required String name,
|
|
||||||
int? value,
|
|
||||||
int? worst,
|
|
||||||
int? thresh,
|
|
||||||
String? whenFailed,
|
|
||||||
dynamic rawValue,
|
|
||||||
String? rawString,
|
|
||||||
required SmartAttributeFlags flags,
|
|
||||||
}) = _SmartAttribute;
|
|
||||||
|
|
||||||
factory SmartAttribute.fromJson(Map<String, dynamic> json) => _$SmartAttributeFromJson(json);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'SmartAttribute(id: $id, name: $name)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class SmartAttributeFlags with _$SmartAttributeFlags {
|
|
||||||
const SmartAttributeFlags._();
|
|
||||||
|
|
||||||
const factory SmartAttributeFlags({
|
|
||||||
int? value,
|
|
||||||
String? string,
|
|
||||||
@Default(false) bool prefailure,
|
|
||||||
@Default(false) bool updatedOnline,
|
|
||||||
@Default(false) bool performance,
|
|
||||||
@Default(false) bool errorRate,
|
|
||||||
@Default(false) bool eventCount,
|
|
||||||
@Default(false) bool autoKeep,
|
|
||||||
}) = _SmartAttributeFlags;
|
|
||||||
|
|
||||||
factory SmartAttributeFlags.fromJson(Map<String, dynamic> json) => _$SmartAttributeFlagsFromJson(json);
|
|
||||||
|
|
||||||
factory SmartAttributeFlags.fromMap(Map<String, dynamic> map) {
|
|
||||||
return SmartAttributeFlags(
|
|
||||||
value: map['value'] as int?,
|
|
||||||
string: map['string']?.toString(),
|
|
||||||
prefailure: map['prefailure'] == true,
|
|
||||||
updatedOnline: map['updated_online'] == true,
|
|
||||||
performance: map['performance'] == true,
|
|
||||||
errorRate: map['error_rate'] == true,
|
|
||||||
eventCount: map['event_count'] == true,
|
|
||||||
autoKeep: map['auto_keep'] == true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'SmartAttributeFlags(value: $value, string: $string)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,489 +0,0 @@
|
|||||||
// dart format width=80
|
|
||||||
// coverage:ignore-file
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
|
||||||
|
|
||||||
part of 'disk_smart.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// dart format off
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$DiskSmart {
|
|
||||||
|
|
||||||
String get device; bool? get healthy; double? get temperature; String? get model; String? get serial; int? get powerOnHours; int? get powerCycleCount; Map<String, dynamic> get rawData; Map<String, SmartAttribute> get smartAttributes;
|
|
||||||
/// Create a copy of DiskSmart
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$DiskSmartCopyWith<DiskSmart> get copyWith => _$DiskSmartCopyWithImpl<DiskSmart>(this as DiskSmart, _$identity);
|
|
||||||
|
|
||||||
/// Serializes this DiskSmart to a JSON map.
|
|
||||||
Map<String, dynamic> toJson();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is DiskSmart&&(identical(other.device, device) || other.device == device)&&(identical(other.healthy, healthy) || other.healthy == healthy)&&(identical(other.temperature, temperature) || other.temperature == temperature)&&(identical(other.model, model) || other.model == model)&&(identical(other.serial, serial) || other.serial == serial)&&(identical(other.powerOnHours, powerOnHours) || other.powerOnHours == powerOnHours)&&(identical(other.powerCycleCount, powerCycleCount) || other.powerCycleCount == powerCycleCount)&&const DeepCollectionEquality().equals(other.rawData, rawData)&&const DeepCollectionEquality().equals(other.smartAttributes, smartAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,device,healthy,temperature,model,serial,powerOnHours,powerCycleCount,const DeepCollectionEquality().hash(rawData),const DeepCollectionEquality().hash(smartAttributes));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $DiskSmartCopyWith<$Res> {
|
|
||||||
factory $DiskSmartCopyWith(DiskSmart value, $Res Function(DiskSmart) _then) = _$DiskSmartCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
String device, bool? healthy, double? temperature, String? model, String? serial, int? powerOnHours, int? powerCycleCount, Map<String, dynamic> rawData, Map<String, SmartAttribute> smartAttributes
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$DiskSmartCopyWithImpl<$Res>
|
|
||||||
implements $DiskSmartCopyWith<$Res> {
|
|
||||||
_$DiskSmartCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final DiskSmart _self;
|
|
||||||
final $Res Function(DiskSmart) _then;
|
|
||||||
|
|
||||||
/// Create a copy of DiskSmart
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? device = null,Object? healthy = freezed,Object? temperature = freezed,Object? model = freezed,Object? serial = freezed,Object? powerOnHours = freezed,Object? powerCycleCount = freezed,Object? rawData = null,Object? smartAttributes = null,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
device: null == device ? _self.device : device // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,healthy: freezed == healthy ? _self.healthy : healthy // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool?,temperature: freezed == temperature ? _self.temperature : temperature // ignore: cast_nullable_to_non_nullable
|
|
||||||
as double?,model: freezed == model ? _self.model : model // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,serial: freezed == serial ? _self.serial : serial // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,powerOnHours: freezed == powerOnHours ? _self.powerOnHours : powerOnHours // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,powerCycleCount: freezed == powerCycleCount ? _self.powerCycleCount : powerCycleCount // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,rawData: null == rawData ? _self.rawData : rawData // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, dynamic>,smartAttributes: null == smartAttributes ? _self.smartAttributes : smartAttributes // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, SmartAttribute>,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@JsonSerializable()
|
|
||||||
|
|
||||||
class _DiskSmart extends DiskSmart {
|
|
||||||
const _DiskSmart({required this.device, this.healthy, this.temperature, this.model, this.serial, this.powerOnHours, this.powerCycleCount, required final Map<String, dynamic> rawData, required final Map<String, SmartAttribute> smartAttributes}): _rawData = rawData,_smartAttributes = smartAttributes,super._();
|
|
||||||
factory _DiskSmart.fromJson(Map<String, dynamic> json) => _$DiskSmartFromJson(json);
|
|
||||||
|
|
||||||
@override final String device;
|
|
||||||
@override final bool? healthy;
|
|
||||||
@override final double? temperature;
|
|
||||||
@override final String? model;
|
|
||||||
@override final String? serial;
|
|
||||||
@override final int? powerOnHours;
|
|
||||||
@override final int? powerCycleCount;
|
|
||||||
final Map<String, dynamic> _rawData;
|
|
||||||
@override Map<String, dynamic> get rawData {
|
|
||||||
if (_rawData is EqualUnmodifiableMapView) return _rawData;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_rawData);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, SmartAttribute> _smartAttributes;
|
|
||||||
@override Map<String, SmartAttribute> get smartAttributes {
|
|
||||||
if (_smartAttributes is EqualUnmodifiableMapView) return _smartAttributes;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(_smartAttributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Create a copy of DiskSmart
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$DiskSmartCopyWith<_DiskSmart> get copyWith => __$DiskSmartCopyWithImpl<_DiskSmart>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$DiskSmartToJson(this, );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DiskSmart&&(identical(other.device, device) || other.device == device)&&(identical(other.healthy, healthy) || other.healthy == healthy)&&(identical(other.temperature, temperature) || other.temperature == temperature)&&(identical(other.model, model) || other.model == model)&&(identical(other.serial, serial) || other.serial == serial)&&(identical(other.powerOnHours, powerOnHours) || other.powerOnHours == powerOnHours)&&(identical(other.powerCycleCount, powerCycleCount) || other.powerCycleCount == powerCycleCount)&&const DeepCollectionEquality().equals(other._rawData, _rawData)&&const DeepCollectionEquality().equals(other._smartAttributes, _smartAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,device,healthy,temperature,model,serial,powerOnHours,powerCycleCount,const DeepCollectionEquality().hash(_rawData),const DeepCollectionEquality().hash(_smartAttributes));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$DiskSmartCopyWith<$Res> implements $DiskSmartCopyWith<$Res> {
|
|
||||||
factory _$DiskSmartCopyWith(_DiskSmart value, $Res Function(_DiskSmart) _then) = __$DiskSmartCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
String device, bool? healthy, double? temperature, String? model, String? serial, int? powerOnHours, int? powerCycleCount, Map<String, dynamic> rawData, Map<String, SmartAttribute> smartAttributes
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$DiskSmartCopyWithImpl<$Res>
|
|
||||||
implements _$DiskSmartCopyWith<$Res> {
|
|
||||||
__$DiskSmartCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _DiskSmart _self;
|
|
||||||
final $Res Function(_DiskSmart) _then;
|
|
||||||
|
|
||||||
/// Create a copy of DiskSmart
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? device = null,Object? healthy = freezed,Object? temperature = freezed,Object? model = freezed,Object? serial = freezed,Object? powerOnHours = freezed,Object? powerCycleCount = freezed,Object? rawData = null,Object? smartAttributes = null,}) {
|
|
||||||
return _then(_DiskSmart(
|
|
||||||
device: null == device ? _self.device : device // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,healthy: freezed == healthy ? _self.healthy : healthy // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool?,temperature: freezed == temperature ? _self.temperature : temperature // ignore: cast_nullable_to_non_nullable
|
|
||||||
as double?,model: freezed == model ? _self.model : model // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,serial: freezed == serial ? _self.serial : serial // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,powerOnHours: freezed == powerOnHours ? _self.powerOnHours : powerOnHours // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,powerCycleCount: freezed == powerCycleCount ? _self.powerCycleCount : powerCycleCount // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,rawData: null == rawData ? _self._rawData : rawData // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, dynamic>,smartAttributes: null == smartAttributes ? _self._smartAttributes : smartAttributes // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, SmartAttribute>,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$SmartAttribute {
|
|
||||||
|
|
||||||
int? get id; String get name; int? get value; int? get worst; int? get thresh; String? get whenFailed; dynamic get rawValue; String? get rawString; SmartAttributeFlags get flags;
|
|
||||||
/// Create a copy of SmartAttribute
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SmartAttributeCopyWith<SmartAttribute> get copyWith => _$SmartAttributeCopyWithImpl<SmartAttribute>(this as SmartAttribute, _$identity);
|
|
||||||
|
|
||||||
/// Serializes this SmartAttribute to a JSON map.
|
|
||||||
Map<String, dynamic> toJson();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SmartAttribute&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.value, value) || other.value == value)&&(identical(other.worst, worst) || other.worst == worst)&&(identical(other.thresh, thresh) || other.thresh == thresh)&&(identical(other.whenFailed, whenFailed) || other.whenFailed == whenFailed)&&const DeepCollectionEquality().equals(other.rawValue, rawValue)&&(identical(other.rawString, rawString) || other.rawString == rawString)&&(identical(other.flags, flags) || other.flags == flags));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,value,worst,thresh,whenFailed,const DeepCollectionEquality().hash(rawValue),rawString,flags);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $SmartAttributeCopyWith<$Res> {
|
|
||||||
factory $SmartAttributeCopyWith(SmartAttribute value, $Res Function(SmartAttribute) _then) = _$SmartAttributeCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
int? id, String name, int? value, int? worst, int? thresh, String? whenFailed, dynamic rawValue, String? rawString, SmartAttributeFlags flags
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$SmartAttributeFlagsCopyWith<$Res> get flags;
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$SmartAttributeCopyWithImpl<$Res>
|
|
||||||
implements $SmartAttributeCopyWith<$Res> {
|
|
||||||
_$SmartAttributeCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final SmartAttribute _self;
|
|
||||||
final $Res Function(SmartAttribute) _then;
|
|
||||||
|
|
||||||
/// Create a copy of SmartAttribute
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = freezed,Object? name = null,Object? value = freezed,Object? worst = freezed,Object? thresh = freezed,Object? whenFailed = freezed,Object? rawValue = freezed,Object? rawString = freezed,Object? flags = null,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,worst: freezed == worst ? _self.worst : worst // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,thresh: freezed == thresh ? _self.thresh : thresh // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,whenFailed: freezed == whenFailed ? _self.whenFailed : whenFailed // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,rawValue: freezed == rawValue ? _self.rawValue : rawValue // ignore: cast_nullable_to_non_nullable
|
|
||||||
as dynamic,rawString: freezed == rawString ? _self.rawString : rawString // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,flags: null == flags ? _self.flags : flags // ignore: cast_nullable_to_non_nullable
|
|
||||||
as SmartAttributeFlags,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
/// Create a copy of SmartAttribute
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SmartAttributeFlagsCopyWith<$Res> get flags {
|
|
||||||
|
|
||||||
return $SmartAttributeFlagsCopyWith<$Res>(_self.flags, (value) {
|
|
||||||
return _then(_self.copyWith(flags: value));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@JsonSerializable()
|
|
||||||
|
|
||||||
class _SmartAttribute extends SmartAttribute {
|
|
||||||
const _SmartAttribute({this.id, required this.name, this.value, this.worst, this.thresh, this.whenFailed, this.rawValue, this.rawString, required this.flags}): super._();
|
|
||||||
factory _SmartAttribute.fromJson(Map<String, dynamic> json) => _$SmartAttributeFromJson(json);
|
|
||||||
|
|
||||||
@override final int? id;
|
|
||||||
@override final String name;
|
|
||||||
@override final int? value;
|
|
||||||
@override final int? worst;
|
|
||||||
@override final int? thresh;
|
|
||||||
@override final String? whenFailed;
|
|
||||||
@override final dynamic rawValue;
|
|
||||||
@override final String? rawString;
|
|
||||||
@override final SmartAttributeFlags flags;
|
|
||||||
|
|
||||||
/// Create a copy of SmartAttribute
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$SmartAttributeCopyWith<_SmartAttribute> get copyWith => __$SmartAttributeCopyWithImpl<_SmartAttribute>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$SmartAttributeToJson(this, );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SmartAttribute&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.value, value) || other.value == value)&&(identical(other.worst, worst) || other.worst == worst)&&(identical(other.thresh, thresh) || other.thresh == thresh)&&(identical(other.whenFailed, whenFailed) || other.whenFailed == whenFailed)&&const DeepCollectionEquality().equals(other.rawValue, rawValue)&&(identical(other.rawString, rawString) || other.rawString == rawString)&&(identical(other.flags, flags) || other.flags == flags));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,value,worst,thresh,whenFailed,const DeepCollectionEquality().hash(rawValue),rawString,flags);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$SmartAttributeCopyWith<$Res> implements $SmartAttributeCopyWith<$Res> {
|
|
||||||
factory _$SmartAttributeCopyWith(_SmartAttribute value, $Res Function(_SmartAttribute) _then) = __$SmartAttributeCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
int? id, String name, int? value, int? worst, int? thresh, String? whenFailed, dynamic rawValue, String? rawString, SmartAttributeFlags flags
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
@override $SmartAttributeFlagsCopyWith<$Res> get flags;
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$SmartAttributeCopyWithImpl<$Res>
|
|
||||||
implements _$SmartAttributeCopyWith<$Res> {
|
|
||||||
__$SmartAttributeCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _SmartAttribute _self;
|
|
||||||
final $Res Function(_SmartAttribute) _then;
|
|
||||||
|
|
||||||
/// Create a copy of SmartAttribute
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = freezed,Object? name = null,Object? value = freezed,Object? worst = freezed,Object? thresh = freezed,Object? whenFailed = freezed,Object? rawValue = freezed,Object? rawString = freezed,Object? flags = null,}) {
|
|
||||||
return _then(_SmartAttribute(
|
|
||||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,worst: freezed == worst ? _self.worst : worst // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,thresh: freezed == thresh ? _self.thresh : thresh // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,whenFailed: freezed == whenFailed ? _self.whenFailed : whenFailed // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,rawValue: freezed == rawValue ? _self.rawValue : rawValue // ignore: cast_nullable_to_non_nullable
|
|
||||||
as dynamic,rawString: freezed == rawString ? _self.rawString : rawString // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,flags: null == flags ? _self.flags : flags // ignore: cast_nullable_to_non_nullable
|
|
||||||
as SmartAttributeFlags,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a copy of SmartAttribute
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SmartAttributeFlagsCopyWith<$Res> get flags {
|
|
||||||
|
|
||||||
return $SmartAttributeFlagsCopyWith<$Res>(_self.flags, (value) {
|
|
||||||
return _then(_self.copyWith(flags: value));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$SmartAttributeFlags {
|
|
||||||
|
|
||||||
int? get value; String? get string; bool get prefailure; bool get updatedOnline; bool get performance; bool get errorRate; bool get eventCount; bool get autoKeep;
|
|
||||||
/// Create a copy of SmartAttributeFlags
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SmartAttributeFlagsCopyWith<SmartAttributeFlags> get copyWith => _$SmartAttributeFlagsCopyWithImpl<SmartAttributeFlags>(this as SmartAttributeFlags, _$identity);
|
|
||||||
|
|
||||||
/// Serializes this SmartAttributeFlags to a JSON map.
|
|
||||||
Map<String, dynamic> toJson();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SmartAttributeFlags&&(identical(other.value, value) || other.value == value)&&(identical(other.string, string) || other.string == string)&&(identical(other.prefailure, prefailure) || other.prefailure == prefailure)&&(identical(other.updatedOnline, updatedOnline) || other.updatedOnline == updatedOnline)&&(identical(other.performance, performance) || other.performance == performance)&&(identical(other.errorRate, errorRate) || other.errorRate == errorRate)&&(identical(other.eventCount, eventCount) || other.eventCount == eventCount)&&(identical(other.autoKeep, autoKeep) || other.autoKeep == autoKeep));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,value,string,prefailure,updatedOnline,performance,errorRate,eventCount,autoKeep);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $SmartAttributeFlagsCopyWith<$Res> {
|
|
||||||
factory $SmartAttributeFlagsCopyWith(SmartAttributeFlags value, $Res Function(SmartAttributeFlags) _then) = _$SmartAttributeFlagsCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
int? value, String? string, bool prefailure, bool updatedOnline, bool performance, bool errorRate, bool eventCount, bool autoKeep
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$SmartAttributeFlagsCopyWithImpl<$Res>
|
|
||||||
implements $SmartAttributeFlagsCopyWith<$Res> {
|
|
||||||
_$SmartAttributeFlagsCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final SmartAttributeFlags _self;
|
|
||||||
final $Res Function(SmartAttributeFlags) _then;
|
|
||||||
|
|
||||||
/// Create a copy of SmartAttributeFlags
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? value = freezed,Object? string = freezed,Object? prefailure = null,Object? updatedOnline = null,Object? performance = null,Object? errorRate = null,Object? eventCount = null,Object? autoKeep = null,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,string: freezed == string ? _self.string : string // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,prefailure: null == prefailure ? _self.prefailure : prefailure // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,updatedOnline: null == updatedOnline ? _self.updatedOnline : updatedOnline // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,performance: null == performance ? _self.performance : performance // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,errorRate: null == errorRate ? _self.errorRate : errorRate // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,eventCount: null == eventCount ? _self.eventCount : eventCount // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,autoKeep: null == autoKeep ? _self.autoKeep : autoKeep // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@JsonSerializable()
|
|
||||||
|
|
||||||
class _SmartAttributeFlags extends SmartAttributeFlags {
|
|
||||||
const _SmartAttributeFlags({this.value, this.string, this.prefailure = false, this.updatedOnline = false, this.performance = false, this.errorRate = false, this.eventCount = false, this.autoKeep = false}): super._();
|
|
||||||
factory _SmartAttributeFlags.fromJson(Map<String, dynamic> json) => _$SmartAttributeFlagsFromJson(json);
|
|
||||||
|
|
||||||
@override final int? value;
|
|
||||||
@override final String? string;
|
|
||||||
@override@JsonKey() final bool prefailure;
|
|
||||||
@override@JsonKey() final bool updatedOnline;
|
|
||||||
@override@JsonKey() final bool performance;
|
|
||||||
@override@JsonKey() final bool errorRate;
|
|
||||||
@override@JsonKey() final bool eventCount;
|
|
||||||
@override@JsonKey() final bool autoKeep;
|
|
||||||
|
|
||||||
/// Create a copy of SmartAttributeFlags
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$SmartAttributeFlagsCopyWith<_SmartAttributeFlags> get copyWith => __$SmartAttributeFlagsCopyWithImpl<_SmartAttributeFlags>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$SmartAttributeFlagsToJson(this, );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SmartAttributeFlags&&(identical(other.value, value) || other.value == value)&&(identical(other.string, string) || other.string == string)&&(identical(other.prefailure, prefailure) || other.prefailure == prefailure)&&(identical(other.updatedOnline, updatedOnline) || other.updatedOnline == updatedOnline)&&(identical(other.performance, performance) || other.performance == performance)&&(identical(other.errorRate, errorRate) || other.errorRate == errorRate)&&(identical(other.eventCount, eventCount) || other.eventCount == eventCount)&&(identical(other.autoKeep, autoKeep) || other.autoKeep == autoKeep));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,value,string,prefailure,updatedOnline,performance,errorRate,eventCount,autoKeep);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$SmartAttributeFlagsCopyWith<$Res> implements $SmartAttributeFlagsCopyWith<$Res> {
|
|
||||||
factory _$SmartAttributeFlagsCopyWith(_SmartAttributeFlags value, $Res Function(_SmartAttributeFlags) _then) = __$SmartAttributeFlagsCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
int? value, String? string, bool prefailure, bool updatedOnline, bool performance, bool errorRate, bool eventCount, bool autoKeep
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$SmartAttributeFlagsCopyWithImpl<$Res>
|
|
||||||
implements _$SmartAttributeFlagsCopyWith<$Res> {
|
|
||||||
__$SmartAttributeFlagsCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _SmartAttributeFlags _self;
|
|
||||||
final $Res Function(_SmartAttributeFlags) _then;
|
|
||||||
|
|
||||||
/// Create a copy of SmartAttributeFlags
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? value = freezed,Object? string = freezed,Object? prefailure = null,Object? updatedOnline = null,Object? performance = null,Object? errorRate = null,Object? eventCount = null,Object? autoKeep = null,}) {
|
|
||||||
return _then(_SmartAttributeFlags(
|
|
||||||
value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int?,string: freezed == string ? _self.string : string // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,prefailure: null == prefailure ? _self.prefailure : prefailure // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,updatedOnline: null == updatedOnline ? _self.updatedOnline : updatedOnline // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,performance: null == performance ? _self.performance : performance // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,errorRate: null == errorRate ? _self.errorRate : errorRate // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,eventCount: null == eventCount ? _self.eventCount : eventCount // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,autoKeep: null == autoKeep ? _self.autoKeep : autoKeep // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// dart format on
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'disk_smart.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
_DiskSmart _$DiskSmartFromJson(Map<String, dynamic> json) => _DiskSmart(
|
|
||||||
device: json['device'] as String,
|
|
||||||
healthy: json['healthy'] as bool?,
|
|
||||||
temperature: (json['temperature'] as num?)?.toDouble(),
|
|
||||||
model: json['model'] as String?,
|
|
||||||
serial: json['serial'] as String?,
|
|
||||||
powerOnHours: (json['powerOnHours'] as num?)?.toInt(),
|
|
||||||
powerCycleCount: (json['powerCycleCount'] as num?)?.toInt(),
|
|
||||||
rawData: json['rawData'] as Map<String, dynamic>,
|
|
||||||
smartAttributes: (json['smartAttributes'] as Map<String, dynamic>).map(
|
|
||||||
(k, e) => MapEntry(k, SmartAttribute.fromJson(e as Map<String, dynamic>)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$DiskSmartToJson(_DiskSmart instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'device': instance.device,
|
|
||||||
'healthy': instance.healthy,
|
|
||||||
'temperature': instance.temperature,
|
|
||||||
'model': instance.model,
|
|
||||||
'serial': instance.serial,
|
|
||||||
'powerOnHours': instance.powerOnHours,
|
|
||||||
'powerCycleCount': instance.powerCycleCount,
|
|
||||||
'rawData': instance.rawData,
|
|
||||||
'smartAttributes': instance.smartAttributes,
|
|
||||||
};
|
|
||||||
|
|
||||||
_SmartAttribute _$SmartAttributeFromJson(Map<String, dynamic> json) =>
|
|
||||||
_SmartAttribute(
|
|
||||||
id: (json['id'] as num?)?.toInt(),
|
|
||||||
name: json['name'] as String,
|
|
||||||
value: (json['value'] as num?)?.toInt(),
|
|
||||||
worst: (json['worst'] as num?)?.toInt(),
|
|
||||||
thresh: (json['thresh'] as num?)?.toInt(),
|
|
||||||
whenFailed: json['whenFailed'] as String?,
|
|
||||||
rawValue: json['rawValue'],
|
|
||||||
rawString: json['rawString'] as String?,
|
|
||||||
flags: SmartAttributeFlags.fromJson(
|
|
||||||
json['flags'] as Map<String, dynamic>,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$SmartAttributeToJson(_SmartAttribute instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'id': instance.id,
|
|
||||||
'name': instance.name,
|
|
||||||
'value': instance.value,
|
|
||||||
'worst': instance.worst,
|
|
||||||
'thresh': instance.thresh,
|
|
||||||
'whenFailed': instance.whenFailed,
|
|
||||||
'rawValue': instance.rawValue,
|
|
||||||
'rawString': instance.rawString,
|
|
||||||
'flags': instance.flags,
|
|
||||||
};
|
|
||||||
|
|
||||||
_SmartAttributeFlags _$SmartAttributeFlagsFromJson(Map<String, dynamic> json) =>
|
|
||||||
_SmartAttributeFlags(
|
|
||||||
value: (json['value'] as num?)?.toInt(),
|
|
||||||
string: json['string'] as String?,
|
|
||||||
prefailure: json['prefailure'] as bool? ?? false,
|
|
||||||
updatedOnline: json['updatedOnline'] as bool? ?? false,
|
|
||||||
performance: json['performance'] as bool? ?? false,
|
|
||||||
errorRate: json['errorRate'] as bool? ?? false,
|
|
||||||
eventCount: json['eventCount'] as bool? ?? false,
|
|
||||||
autoKeep: json['autoKeep'] as bool? ?? false,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$SmartAttributeFlagsToJson(
|
|
||||||
_SmartAttributeFlags instance,
|
|
||||||
) => <String, dynamic>{
|
|
||||||
'value': instance.value,
|
|
||||||
'string': instance.string,
|
|
||||||
'prefailure': instance.prefailure,
|
|
||||||
'updatedOnline': instance.updatedOnline,
|
|
||||||
'performance': instance.performance,
|
|
||||||
'errorRate': instance.errorRate,
|
|
||||||
'eventCount': instance.eventCount,
|
|
||||||
'autoKeep': instance.autoKeep,
|
|
||||||
};
|
|
||||||
@@ -11,7 +11,6 @@ enum Dist {
|
|||||||
alpine,
|
alpine,
|
||||||
rocky,
|
rocky,
|
||||||
deepin,
|
deepin,
|
||||||
coreelec,
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: unintended_html_in_doc_comment
|
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
import 'package:server_box/data/model/server/time_seq.dart';
|
import 'package:server_box/data/model/server/time_seq.dart';
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
part 'private_key_info.g.dart';
|
part 'private_key_info.g.dart';
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
@HiveType(typeId: 1)
|
||||||
class PrivateKeyInfo {
|
class PrivateKeyInfo {
|
||||||
|
@HiveField(0)
|
||||||
final String id;
|
final String id;
|
||||||
@JsonKey(name: 'private_key')
|
@JsonKey(name: 'private_key')
|
||||||
|
@HiveField(1)
|
||||||
final String key;
|
final String key;
|
||||||
|
|
||||||
const PrivateKeyInfo({
|
const PrivateKeyInfo({
|
||||||
@@ -13,7 +17,8 @@ class PrivateKeyInfo {
|
|||||||
required this.key,
|
required this.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory PrivateKeyInfo.fromJson(Map<String, dynamic> json) => _$PrivateKeyInfoFromJson(json);
|
factory PrivateKeyInfo.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$PrivateKeyInfoFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$PrivateKeyInfoToJson(this);
|
Map<String, dynamic> toJson() => _$PrivateKeyInfoToJson(this);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,47 @@
|
|||||||
|
|
||||||
part of 'private_key_info.dart';
|
part of 'private_key_info.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class PrivateKeyInfoAdapter extends TypeAdapter<PrivateKeyInfo> {
|
||||||
|
@override
|
||||||
|
final int typeId = 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
PrivateKeyInfo read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return PrivateKeyInfo(
|
||||||
|
id: fields[0] as String,
|
||||||
|
key: fields[1] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, PrivateKeyInfo obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(2)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.id)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is PrivateKeyInfoAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
@@ -13,4 +54,7 @@ PrivateKeyInfo _$PrivateKeyInfoFromJson(Map<String, dynamic> json) =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$PrivateKeyInfoToJson(PrivateKeyInfo instance) =>
|
Map<String, dynamic> _$PrivateKeyInfoToJson(PrivateKeyInfo instance) =>
|
||||||
<String, dynamic>{'id': instance.id, 'private_key': instance.key};
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'private_key': instance.key,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:server_box/data/model/app/error.dart';
|
||||||
import 'package:server_box/data/model/app/shell_func.dart';
|
import 'package:server_box/data/model/app/shell_func.dart';
|
||||||
import 'package:server_box/data/model/server/battery.dart';
|
import 'package:server_box/data/model/server/battery.dart';
|
||||||
import 'package:server_box/data/model/server/conn.dart';
|
import 'package:server_box/data/model/server/conn.dart';
|
||||||
import 'package:server_box/data/model/server/cpu.dart';
|
import 'package:server_box/data/model/server/cpu.dart';
|
||||||
import 'package:server_box/data/model/server/disk.dart';
|
import 'package:server_box/data/model/server/disk.dart';
|
||||||
import 'package:server_box/data/model/server/disk_smart.dart';
|
|
||||||
import 'package:server_box/data/model/server/memory.dart';
|
import 'package:server_box/data/model/server/memory.dart';
|
||||||
import 'package:server_box/data/model/server/net_speed.dart';
|
import 'package:server_box/data/model/server/net_speed.dart';
|
||||||
import 'package:server_box/data/model/server/nvdia.dart';
|
import 'package:server_box/data/model/server/nvdia.dart';
|
||||||
@@ -20,7 +19,12 @@ class Server {
|
|||||||
SSHClient? client;
|
SSHClient? client;
|
||||||
ServerConn conn;
|
ServerConn conn;
|
||||||
|
|
||||||
Server(this.spi, this.status, this.conn, {this.client});
|
Server(
|
||||||
|
this.spi,
|
||||||
|
this.status,
|
||||||
|
this.conn, {
|
||||||
|
this.client,
|
||||||
|
});
|
||||||
|
|
||||||
bool get needGenClient => conn < ServerConn.connecting;
|
bool get needGenClient => conn < ServerConn.connecting;
|
||||||
|
|
||||||
@@ -40,7 +44,6 @@ class ServerStatus {
|
|||||||
SystemType system;
|
SystemType system;
|
||||||
Err? err;
|
Err? err;
|
||||||
DiskIO diskIO;
|
DiskIO diskIO;
|
||||||
List<DiskSmart> diskSmart;
|
|
||||||
List<NvidiaSmiItem>? nvidia;
|
List<NvidiaSmiItem>? nvidia;
|
||||||
final List<Battery> batteries = [];
|
final List<Battery> batteries = [];
|
||||||
final Map<StatusCmdType, String> more = {};
|
final Map<StatusCmdType, String> more = {};
|
||||||
@@ -58,7 +61,6 @@ class ServerStatus {
|
|||||||
required this.temps,
|
required this.temps,
|
||||||
required this.system,
|
required this.system,
|
||||||
required this.diskIO,
|
required this.diskIO,
|
||||||
this.diskSmart = const [],
|
|
||||||
this.err,
|
this.err,
|
||||||
this.nvidia,
|
this.nvidia,
|
||||||
this.diskUsage,
|
this.diskUsage,
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:server_box/data/model/app/error.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:server_box/data/model/server/custom.dart';
|
import 'package:server_box/data/model/server/custom.dart';
|
||||||
import 'package:server_box/data/model/server/server.dart';
|
import 'package:server_box/data/model/server/server.dart';
|
||||||
import 'package:server_box/data/model/server/wol_cfg.dart';
|
import 'package:server_box/data/model/server/wol_cfg.dart';
|
||||||
import 'package:server_box/data/provider/server.dart';
|
import 'package:server_box/data/provider/server.dart';
|
||||||
import 'package:server_box/data/store/server.dart';
|
|
||||||
|
|
||||||
part 'server_private_info.freezed.dart';
|
import 'package:server_box/data/model/app/error.dart';
|
||||||
|
|
||||||
part 'server_private_info.g.dart';
|
part 'server_private_info.g.dart';
|
||||||
|
|
||||||
/// In the first version, it's called `ServerPrivateInfo` which was designed to
|
/// In the first version, it's called `ServerPrivateInfo` which was designed to
|
||||||
@@ -18,75 +18,79 @@ part 'server_private_info.g.dart';
|
|||||||
/// Some params named as `spi` in the codebase which is the abbreviation of `ServerPrivateInfo`.
|
/// Some params named as `spi` in the codebase which is the abbreviation of `ServerPrivateInfo`.
|
||||||
///
|
///
|
||||||
/// Nowaday, more fields are added to this class, and it's renamed to `Spi`.
|
/// Nowaday, more fields are added to this class, and it's renamed to `Spi`.
|
||||||
@freezed
|
@JsonSerializable()
|
||||||
abstract class Spi with _$Spi {
|
@HiveType(typeId: 3)
|
||||||
const Spi._();
|
class Spi {
|
||||||
|
@HiveField(0)
|
||||||
|
final String name;
|
||||||
|
@HiveField(1)
|
||||||
|
final String ip;
|
||||||
|
@HiveField(2)
|
||||||
|
final int port;
|
||||||
|
@HiveField(3)
|
||||||
|
final String user;
|
||||||
|
@HiveField(4)
|
||||||
|
final String? pwd;
|
||||||
|
|
||||||
@JsonSerializable(includeIfNull: false)
|
/// [id] of private key
|
||||||
const factory Spi({
|
@JsonKey(name: 'pubKeyId')
|
||||||
required String name,
|
@HiveField(5)
|
||||||
required String ip,
|
final String? keyId;
|
||||||
required int port,
|
@HiveField(6)
|
||||||
required String user,
|
final List<String>? tags;
|
||||||
String? pwd,
|
@HiveField(7)
|
||||||
|
final String? alterUrl;
|
||||||
|
@HiveField(8, defaultValue: true)
|
||||||
|
final bool autoConnect;
|
||||||
|
|
||||||
/// [id] of private key
|
/// [id] of the jump server
|
||||||
@JsonKey(name: 'pubKeyId') String? keyId,
|
@HiveField(9)
|
||||||
List<String>? tags,
|
final String? jumpId;
|
||||||
String? alterUrl,
|
|
||||||
@Default(true) bool autoConnect,
|
|
||||||
|
|
||||||
/// [id] of the jump server
|
@HiveField(10)
|
||||||
String? jumpId,
|
final ServerCustom? custom;
|
||||||
ServerCustom? custom,
|
|
||||||
WakeOnLanCfg? wolCfg,
|
|
||||||
|
|
||||||
/// It only applies to SSH terminal.
|
@HiveField(11)
|
||||||
Map<String, String>? envs,
|
final WakeOnLanCfg? wolCfg;
|
||||||
@Default('') @JsonKey(fromJson: Spi.parseId) String id,
|
|
||||||
}) = _Spi;
|
/// It only applies to SSH terminal.
|
||||||
|
@HiveField(12)
|
||||||
|
final Map<String, String>? envs;
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
const Spi({
|
||||||
|
required this.name,
|
||||||
|
required this.ip,
|
||||||
|
required this.port,
|
||||||
|
required this.user,
|
||||||
|
required this.pwd,
|
||||||
|
this.keyId,
|
||||||
|
this.tags,
|
||||||
|
this.alterUrl,
|
||||||
|
this.autoConnect = true,
|
||||||
|
this.jumpId,
|
||||||
|
this.custom,
|
||||||
|
this.wolCfg,
|
||||||
|
this.envs,
|
||||||
|
}) : id = '$user@$ip:$port';
|
||||||
|
|
||||||
factory Spi.fromJson(Map<String, dynamic> json) => _$SpiFromJson(json);
|
factory Spi.fromJson(Map<String, dynamic> json) => _$SpiFromJson(json);
|
||||||
|
|
||||||
@override
|
Map<String, dynamic> toJson() => _$SpiToJson(this);
|
||||||
String toString() => 'Spi<$oldId>';
|
|
||||||
|
|
||||||
static String parseId(Object? id) {
|
@override
|
||||||
if (id == null || id is! String || id.isEmpty) return ShortId.generate();
|
String toString() => id;
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Spix on Spi {
|
extension Spix on Spi {
|
||||||
/// After upgrading to >= 1155, this field is only recommended to be used
|
|
||||||
/// for displaying the server name.
|
|
||||||
String get oldId => '$user@$ip:$port';
|
|
||||||
|
|
||||||
/// Save the [Spi] to the local storage.
|
|
||||||
void save() => ServerStore.instance.put(this);
|
|
||||||
|
|
||||||
/// Migrate the [oldId] to the new generated [id] by [ShortId.generate].
|
|
||||||
///
|
|
||||||
/// Returns:
|
|
||||||
/// - `null` if the [id] is not empty.
|
|
||||||
/// - The new [id] if the [id] is empty.
|
|
||||||
String? migrateId() {
|
|
||||||
if (id.isNotEmpty) return null;
|
|
||||||
ServerStore.instance.delete(oldId);
|
|
||||||
final newSpi = copyWith(id: ShortId.generate());
|
|
||||||
newSpi.save();
|
|
||||||
return newSpi.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
String toJsonString() => json.encode(toJson());
|
String toJsonString() => json.encode(toJson());
|
||||||
|
|
||||||
VNode<Server>? get server => ServerProvider.pick(spi: this);
|
VNode<Server>? get server => ServerProvider.pick(spi: this);
|
||||||
VNode<Server>? get jumpServer => ServerProvider.pick(id: jumpId);
|
VNode<Server>? get jumpServer => ServerProvider.pick(id: jumpId);
|
||||||
|
|
||||||
bool shouldReconnect(Spi old) {
|
bool shouldReconnect(Spi old) {
|
||||||
return user != old.user ||
|
return id != old.id ||
|
||||||
ip != old.ip ||
|
|
||||||
port != old.port ||
|
|
||||||
pwd != old.pwd ||
|
pwd != old.pwd ||
|
||||||
keyId != old.keyId ||
|
keyId != old.keyId ||
|
||||||
alterUrl != old.alterUrl ||
|
alterUrl != old.alterUrl ||
|
||||||
@@ -118,27 +122,27 @@ extension Spix on Spi {
|
|||||||
/// Just for showing the struct of the class.
|
/// Just for showing the struct of the class.
|
||||||
///
|
///
|
||||||
/// **NOT** the default value.
|
/// **NOT** the default value.
|
||||||
static final example = Spi(
|
static const example = Spi(
|
||||||
name: 'name',
|
name: 'name',
|
||||||
ip: 'ip',
|
ip: 'ip',
|
||||||
port: 22,
|
port: 22,
|
||||||
user: 'root',
|
user: 'root',
|
||||||
pwd: 'pwd',
|
pwd: 'pwd',
|
||||||
keyId: 'private_key_id',
|
keyId: 'private_key_id',
|
||||||
tags: ['tag1', 'tag2'],
|
tags: ['tag1', 'tag2'],
|
||||||
alterUrl: 'user@ip:port',
|
alterUrl: 'user@ip:port',
|
||||||
autoConnect: true,
|
autoConnect: true,
|
||||||
jumpId: 'jump_server_id',
|
jumpId: 'jump_server_id',
|
||||||
custom: ServerCustom(
|
custom: ServerCustom(
|
||||||
pveAddr: 'http://localhost:8006',
|
pveAddr: 'http://localhost:8006',
|
||||||
pveIgnoreCert: false,
|
pveIgnoreCert: false,
|
||||||
cmds: {
|
cmds: {
|
||||||
'echo': 'echo hello',
|
'echo': 'echo hello',
|
||||||
},
|
},
|
||||||
preferTempDev: 'nvme-pci-0400',
|
preferTempDev: 'nvme-pci-0400',
|
||||||
logoUrl: 'https://example.com/logo.png',
|
logoUrl: 'https://example.com/logo.png',
|
||||||
),
|
),
|
||||||
id: 'id');
|
);
|
||||||
|
|
||||||
bool get isRoot => user == 'root';
|
bool get isRoot => user == 'root';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,202 +0,0 @@
|
|||||||
// dart format width=80
|
|
||||||
// coverage:ignore-file
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
|
||||||
|
|
||||||
part of 'server_private_info.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// dart format off
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$Spi {
|
|
||||||
|
|
||||||
String get name; String get ip; int get port; String get user; String? get pwd;/// [id] of private key
|
|
||||||
@JsonKey(name: 'pubKeyId') String? get keyId; List<String>? get tags; String? get alterUrl; bool get autoConnect;/// [id] of the jump server
|
|
||||||
String? get jumpId; ServerCustom? get custom; WakeOnLanCfg? get wolCfg;/// It only applies to SSH terminal.
|
|
||||||
Map<String, String>? get envs;@JsonKey(fromJson: Spi.parseId) String get id;
|
|
||||||
/// Create a copy of Spi
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SpiCopyWith<Spi> get copyWith => _$SpiCopyWithImpl<Spi>(this as Spi, _$identity);
|
|
||||||
|
|
||||||
/// Serializes this Spi to a JSON map.
|
|
||||||
Map<String, dynamic> toJson();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is Spi&&(identical(other.name, name) || other.name == name)&&(identical(other.ip, ip) || other.ip == ip)&&(identical(other.port, port) || other.port == port)&&(identical(other.user, user) || other.user == user)&&(identical(other.pwd, pwd) || other.pwd == pwd)&&(identical(other.keyId, keyId) || other.keyId == keyId)&&const DeepCollectionEquality().equals(other.tags, tags)&&(identical(other.alterUrl, alterUrl) || other.alterUrl == alterUrl)&&(identical(other.autoConnect, autoConnect) || other.autoConnect == autoConnect)&&(identical(other.jumpId, jumpId) || other.jumpId == jumpId)&&(identical(other.custom, custom) || other.custom == custom)&&(identical(other.wolCfg, wolCfg) || other.wolCfg == wolCfg)&&const DeepCollectionEquality().equals(other.envs, envs)&&(identical(other.id, id) || other.id == id));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,name,ip,port,user,pwd,keyId,const DeepCollectionEquality().hash(tags),alterUrl,autoConnect,jumpId,custom,wolCfg,const DeepCollectionEquality().hash(envs),id);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $SpiCopyWith<$Res> {
|
|
||||||
factory $SpiCopyWith(Spi value, $Res Function(Spi) _then) = _$SpiCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
String name, String ip, int port, String user, String? pwd,@JsonKey(name: 'pubKeyId') String? keyId, List<String>? tags, String? alterUrl, bool autoConnect, String? jumpId, ServerCustom? custom, WakeOnLanCfg? wolCfg, Map<String, String>? envs,@JsonKey(fromJson: Spi.parseId) String id
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$SpiCopyWithImpl<$Res>
|
|
||||||
implements $SpiCopyWith<$Res> {
|
|
||||||
_$SpiCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final Spi _self;
|
|
||||||
final $Res Function(Spi) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Spi
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? ip = null,Object? port = null,Object? user = null,Object? pwd = freezed,Object? keyId = freezed,Object? tags = freezed,Object? alterUrl = freezed,Object? autoConnect = null,Object? jumpId = freezed,Object? custom = freezed,Object? wolCfg = freezed,Object? envs = freezed,Object? id = null,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,ip: null == ip ? _self.ip : ip // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,user: null == user ? _self.user : user // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,pwd: freezed == pwd ? _self.pwd : pwd // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,keyId: freezed == keyId ? _self.keyId : keyId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,tags: freezed == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
|
|
||||||
as List<String>?,alterUrl: freezed == alterUrl ? _self.alterUrl : alterUrl // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,autoConnect: null == autoConnect ? _self.autoConnect : autoConnect // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,jumpId: freezed == jumpId ? _self.jumpId : jumpId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,custom: freezed == custom ? _self.custom : custom // ignore: cast_nullable_to_non_nullable
|
|
||||||
as ServerCustom?,wolCfg: freezed == wolCfg ? _self.wolCfg : wolCfg // ignore: cast_nullable_to_non_nullable
|
|
||||||
as WakeOnLanCfg?,envs: freezed == envs ? _self.envs : envs // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, String>?,id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
@JsonSerializable(includeIfNull: false)
|
|
||||||
class _Spi extends Spi {
|
|
||||||
const _Spi({required this.name, required this.ip, required this.port, required this.user, this.pwd, @JsonKey(name: 'pubKeyId') this.keyId, final List<String>? tags, this.alterUrl, this.autoConnect = true, this.jumpId, this.custom, this.wolCfg, final Map<String, String>? envs, @JsonKey(fromJson: Spi.parseId) this.id = ''}): _tags = tags,_envs = envs,super._();
|
|
||||||
factory _Spi.fromJson(Map<String, dynamic> json) => _$SpiFromJson(json);
|
|
||||||
|
|
||||||
@override final String name;
|
|
||||||
@override final String ip;
|
|
||||||
@override final int port;
|
|
||||||
@override final String user;
|
|
||||||
@override final String? pwd;
|
|
||||||
/// [id] of private key
|
|
||||||
@override@JsonKey(name: 'pubKeyId') final String? keyId;
|
|
||||||
final List<String>? _tags;
|
|
||||||
@override List<String>? get tags {
|
|
||||||
final value = _tags;
|
|
||||||
if (value == null) return null;
|
|
||||||
if (_tags is EqualUnmodifiableListView) return _tags;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableListView(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override final String? alterUrl;
|
|
||||||
@override@JsonKey() final bool autoConnect;
|
|
||||||
/// [id] of the jump server
|
|
||||||
@override final String? jumpId;
|
|
||||||
@override final ServerCustom? custom;
|
|
||||||
@override final WakeOnLanCfg? wolCfg;
|
|
||||||
/// It only applies to SSH terminal.
|
|
||||||
final Map<String, String>? _envs;
|
|
||||||
/// It only applies to SSH terminal.
|
|
||||||
@override Map<String, String>? get envs {
|
|
||||||
final value = _envs;
|
|
||||||
if (value == null) return null;
|
|
||||||
if (_envs is EqualUnmodifiableMapView) return _envs;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableMapView(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override@JsonKey(fromJson: Spi.parseId) final String id;
|
|
||||||
|
|
||||||
/// Create a copy of Spi
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$SpiCopyWith<_Spi> get copyWith => __$SpiCopyWithImpl<_Spi>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$SpiToJson(this, );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Spi&&(identical(other.name, name) || other.name == name)&&(identical(other.ip, ip) || other.ip == ip)&&(identical(other.port, port) || other.port == port)&&(identical(other.user, user) || other.user == user)&&(identical(other.pwd, pwd) || other.pwd == pwd)&&(identical(other.keyId, keyId) || other.keyId == keyId)&&const DeepCollectionEquality().equals(other._tags, _tags)&&(identical(other.alterUrl, alterUrl) || other.alterUrl == alterUrl)&&(identical(other.autoConnect, autoConnect) || other.autoConnect == autoConnect)&&(identical(other.jumpId, jumpId) || other.jumpId == jumpId)&&(identical(other.custom, custom) || other.custom == custom)&&(identical(other.wolCfg, wolCfg) || other.wolCfg == wolCfg)&&const DeepCollectionEquality().equals(other._envs, _envs)&&(identical(other.id, id) || other.id == id));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,name,ip,port,user,pwd,keyId,const DeepCollectionEquality().hash(_tags),alterUrl,autoConnect,jumpId,custom,wolCfg,const DeepCollectionEquality().hash(_envs),id);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$SpiCopyWith<$Res> implements $SpiCopyWith<$Res> {
|
|
||||||
factory _$SpiCopyWith(_Spi value, $Res Function(_Spi) _then) = __$SpiCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
String name, String ip, int port, String user, String? pwd,@JsonKey(name: 'pubKeyId') String? keyId, List<String>? tags, String? alterUrl, bool autoConnect, String? jumpId, ServerCustom? custom, WakeOnLanCfg? wolCfg, Map<String, String>? envs,@JsonKey(fromJson: Spi.parseId) String id
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$SpiCopyWithImpl<$Res>
|
|
||||||
implements _$SpiCopyWith<$Res> {
|
|
||||||
__$SpiCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _Spi _self;
|
|
||||||
final $Res Function(_Spi) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Spi
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? ip = null,Object? port = null,Object? user = null,Object? pwd = freezed,Object? keyId = freezed,Object? tags = freezed,Object? alterUrl = freezed,Object? autoConnect = null,Object? jumpId = freezed,Object? custom = freezed,Object? wolCfg = freezed,Object? envs = freezed,Object? id = null,}) {
|
|
||||||
return _then(_Spi(
|
|
||||||
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,ip: null == ip ? _self.ip : ip // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,user: null == user ? _self.user : user // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,pwd: freezed == pwd ? _self.pwd : pwd // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,keyId: freezed == keyId ? _self.keyId : keyId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,tags: freezed == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
|
|
||||||
as List<String>?,alterUrl: freezed == alterUrl ? _self.alterUrl : alterUrl // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,autoConnect: null == autoConnect ? _self.autoConnect : autoConnect // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,jumpId: freezed == jumpId ? _self.jumpId : jumpId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,custom: freezed == custom ? _self.custom : custom // ignore: cast_nullable_to_non_nullable
|
|
||||||
as ServerCustom?,wolCfg: freezed == wolCfg ? _self.wolCfg : wolCfg // ignore: cast_nullable_to_non_nullable
|
|
||||||
as WakeOnLanCfg?,envs: freezed == envs ? _self._envs : envs // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Map<String, String>?,id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// dart format on
|
|
||||||
@@ -2,46 +2,118 @@
|
|||||||
|
|
||||||
part of 'server_private_info.dart';
|
part of 'server_private_info.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class SpiAdapter extends TypeAdapter<Spi> {
|
||||||
|
@override
|
||||||
|
final int typeId = 3;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Spi read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return Spi(
|
||||||
|
name: fields[0] as String,
|
||||||
|
ip: fields[1] as String,
|
||||||
|
port: fields[2] as int,
|
||||||
|
user: fields[3] as String,
|
||||||
|
pwd: fields[4] as String?,
|
||||||
|
keyId: fields[5] as String?,
|
||||||
|
tags: (fields[6] as List?)?.cast<String>(),
|
||||||
|
alterUrl: fields[7] as String?,
|
||||||
|
autoConnect: fields[8] == null ? true : fields[8] as bool,
|
||||||
|
jumpId: fields[9] as String?,
|
||||||
|
custom: fields[10] as ServerCustom?,
|
||||||
|
wolCfg: fields[11] as WakeOnLanCfg?,
|
||||||
|
envs: (fields[12] as Map?)?.cast<String, String>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, Spi obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(13)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.name)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.ip)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.port)
|
||||||
|
..writeByte(3)
|
||||||
|
..write(obj.user)
|
||||||
|
..writeByte(4)
|
||||||
|
..write(obj.pwd)
|
||||||
|
..writeByte(5)
|
||||||
|
..write(obj.keyId)
|
||||||
|
..writeByte(6)
|
||||||
|
..write(obj.tags)
|
||||||
|
..writeByte(7)
|
||||||
|
..write(obj.alterUrl)
|
||||||
|
..writeByte(8)
|
||||||
|
..write(obj.autoConnect)
|
||||||
|
..writeByte(9)
|
||||||
|
..write(obj.jumpId)
|
||||||
|
..writeByte(10)
|
||||||
|
..write(obj.custom)
|
||||||
|
..writeByte(11)
|
||||||
|
..write(obj.wolCfg)
|
||||||
|
..writeByte(12)
|
||||||
|
..write(obj.envs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is SpiAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
_Spi _$SpiFromJson(Map<String, dynamic> json) => _Spi(
|
Spi _$SpiFromJson(Map<String, dynamic> json) => Spi(
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
ip: json['ip'] as String,
|
ip: json['ip'] as String,
|
||||||
port: (json['port'] as num).toInt(),
|
port: (json['port'] as num).toInt(),
|
||||||
user: json['user'] as String,
|
user: json['user'] as String,
|
||||||
pwd: json['pwd'] as String?,
|
pwd: json['pwd'] as String?,
|
||||||
keyId: json['pubKeyId'] as String?,
|
keyId: json['pubKeyId'] as String?,
|
||||||
tags: (json['tags'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
tags: (json['tags'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||||
alterUrl: json['alterUrl'] as String?,
|
alterUrl: json['alterUrl'] as String?,
|
||||||
autoConnect: json['autoConnect'] as bool? ?? true,
|
autoConnect: json['autoConnect'] as bool? ?? true,
|
||||||
jumpId: json['jumpId'] as String?,
|
jumpId: json['jumpId'] as String?,
|
||||||
custom: json['custom'] == null
|
custom: json['custom'] == null
|
||||||
? null
|
? null
|
||||||
: ServerCustom.fromJson(json['custom'] as Map<String, dynamic>),
|
: ServerCustom.fromJson(json['custom'] as Map<String, dynamic>),
|
||||||
wolCfg: json['wolCfg'] == null
|
wolCfg: json['wolCfg'] == null
|
||||||
? null
|
? null
|
||||||
: WakeOnLanCfg.fromJson(json['wolCfg'] as Map<String, dynamic>),
|
: WakeOnLanCfg.fromJson(json['wolCfg'] as Map<String, dynamic>),
|
||||||
envs: (json['envs'] as Map<String, dynamic>?)?.map(
|
envs: (json['envs'] as Map<String, dynamic>?)?.map(
|
||||||
(k, e) => MapEntry(k, e as String),
|
(k, e) => MapEntry(k, e as String),
|
||||||
),
|
),
|
||||||
id: json['id'] == null ? '' : Spi.parseId(json['id']),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$SpiToJson(_Spi instance) => <String, dynamic>{
|
Map<String, dynamic> _$SpiToJson(Spi instance) => <String, dynamic>{
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'ip': instance.ip,
|
'ip': instance.ip,
|
||||||
'port': instance.port,
|
'port': instance.port,
|
||||||
'user': instance.user,
|
'user': instance.user,
|
||||||
if (instance.pwd case final value?) 'pwd': value,
|
'pwd': instance.pwd,
|
||||||
if (instance.keyId case final value?) 'pubKeyId': value,
|
'pubKeyId': instance.keyId,
|
||||||
if (instance.tags case final value?) 'tags': value,
|
'tags': instance.tags,
|
||||||
if (instance.alterUrl case final value?) 'alterUrl': value,
|
'alterUrl': instance.alterUrl,
|
||||||
'autoConnect': instance.autoConnect,
|
'autoConnect': instance.autoConnect,
|
||||||
if (instance.jumpId case final value?) 'jumpId': value,
|
'jumpId': instance.jumpId,
|
||||||
if (instance.custom case final value?) 'custom': value,
|
'custom': instance.custom,
|
||||||
if (instance.wolCfg case final value?) 'wolCfg': value,
|
'wolCfg': instance.wolCfg,
|
||||||
if (instance.envs case final value?) 'envs': value,
|
'envs': instance.envs,
|
||||||
'id': instance.id,
|
};
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:server_box/data/model/app/shell_func.dart';
|
|
||||||
import 'package:server_box/data/model/server/battery.dart';
|
import 'package:server_box/data/model/server/battery.dart';
|
||||||
import 'package:server_box/data/model/server/conn.dart';
|
|
||||||
import 'package:server_box/data/model/server/cpu.dart';
|
|
||||||
import 'package:server_box/data/model/server/disk.dart';
|
|
||||||
import 'package:server_box/data/model/server/disk_smart.dart';
|
|
||||||
import 'package:server_box/data/model/server/memory.dart';
|
|
||||||
import 'package:server_box/data/model/server/net_speed.dart';
|
|
||||||
import 'package:server_box/data/model/server/nvdia.dart';
|
import 'package:server_box/data/model/server/nvdia.dart';
|
||||||
import 'package:server_box/data/model/server/sensors.dart';
|
import 'package:server_box/data/model/server/sensors.dart';
|
||||||
import 'package:server_box/data/model/server/server.dart';
|
import 'package:server_box/data/model/server/server.dart';
|
||||||
import 'package:server_box/data/model/server/system.dart';
|
import 'package:server_box/data/model/server/system.dart';
|
||||||
|
|
||||||
|
import 'package:server_box/data/model/app/shell_func.dart';
|
||||||
|
import 'package:server_box/data/model/server/cpu.dart';
|
||||||
|
import 'package:server_box/data/model/server/disk.dart';
|
||||||
|
import 'package:server_box/data/model/server/memory.dart';
|
||||||
|
import 'package:server_box/data/model/server/net_speed.dart';
|
||||||
|
import 'package:server_box/data/model/server/conn.dart';
|
||||||
|
|
||||||
class ServerStatusUpdateReq {
|
class ServerStatusUpdateReq {
|
||||||
final ServerStatus ss;
|
final ServerStatus ss;
|
||||||
final List<String> segments;
|
final List<String> segments;
|
||||||
@@ -38,8 +38,7 @@ Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
|
|||||||
Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
||||||
final segments = req.segments;
|
final segments = req.segments;
|
||||||
|
|
||||||
final time =
|
final time = int.tryParse(StatusCmdType.time.find(segments)) ??
|
||||||
int.tryParse(StatusCmdType.time.find(segments)) ??
|
|
||||||
DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -50,7 +49,9 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final sys = _parseSysVer(StatusCmdType.sys.find(segments));
|
final sys = _parseSysVer(
|
||||||
|
StatusCmdType.sys.find(segments),
|
||||||
|
);
|
||||||
if (sys != null) {
|
if (sys != null) {
|
||||||
req.ss.more[StatusCmdType.sys] = sys;
|
req.ss.more[StatusCmdType.sys] = sys;
|
||||||
}
|
}
|
||||||
@@ -130,13 +131,6 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
|||||||
Loggers.app.warning(e, s);
|
Loggers.app.warning(e, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
final smarts = DiskSmart.parse(StatusCmdType.diskSmart.find(segments));
|
|
||||||
req.ss.diskSmart = smarts;
|
|
||||||
} catch (e, s) {
|
|
||||||
Loggers.app.warning(e, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.ss.nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments));
|
req.ss.nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments));
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
|||||||
@@ -1,37 +1,42 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||||
import 'package:xterm/core.dart';
|
import 'package:xterm/core.dart';
|
||||||
|
|
||||||
part 'snippet.g.dart';
|
part 'snippet.g.dart';
|
||||||
part 'snippet.freezed.dart';
|
|
||||||
|
|
||||||
@freezed
|
@JsonSerializable()
|
||||||
abstract class Snippet with _$Snippet {
|
@HiveType(typeId: 2)
|
||||||
const factory Snippet({
|
class Snippet {
|
||||||
required String name,
|
@HiveField(0)
|
||||||
required String script,
|
final String name;
|
||||||
List<String>? tags,
|
@HiveField(1)
|
||||||
String? note,
|
final String script;
|
||||||
|
@HiveField(2)
|
||||||
|
final List<String>? tags;
|
||||||
|
@HiveField(3)
|
||||||
|
final String? note;
|
||||||
|
|
||||||
/// List of server id that this snippet should be auto run on
|
/// List of server id that this snippet should be auto run on
|
||||||
List<String>? autoRunOn,
|
@HiveField(4)
|
||||||
}) = _Snippet;
|
final List<String>? autoRunOn;
|
||||||
|
|
||||||
factory Snippet.fromJson(Map<String, dynamic> json) => _$SnippetFromJson(json);
|
const Snippet({
|
||||||
|
required this.name,
|
||||||
|
required this.script,
|
||||||
|
this.tags,
|
||||||
|
this.note,
|
||||||
|
this.autoRunOn,
|
||||||
|
});
|
||||||
|
|
||||||
static const example = Snippet(
|
factory Snippet.fromJson(Map<String, dynamic> json) =>
|
||||||
name: 'example',
|
_$SnippetFromJson(json);
|
||||||
script: 'echo hello',
|
|
||||||
tags: ['tag'],
|
Map<String, dynamic> toJson() => _$SnippetToJson(this);
|
||||||
note: 'note',
|
|
||||||
autoRunOn: ['server_id'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension SnippetX on Snippet {
|
|
||||||
static final fmtFinder = RegExp(r'\$\{[^{}]+\}');
|
static final fmtFinder = RegExp(r'\$\{[^{}]+\}');
|
||||||
|
|
||||||
String fmtWithSpi(Spi spi) {
|
String fmtWithSpi(Spi spi) {
|
||||||
@@ -170,6 +175,14 @@ extension SnippetX on Snippet {
|
|||||||
r'${ctrl': TerminalKey.control,
|
r'${ctrl': TerminalKey.control,
|
||||||
r'${alt': TerminalKey.alt,
|
r'${alt': TerminalKey.alt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const example = Snippet(
|
||||||
|
name: 'example',
|
||||||
|
script: 'echo hello',
|
||||||
|
tags: ['tag'],
|
||||||
|
note: 'note',
|
||||||
|
autoRunOn: ['server_id'],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SnippetResult {
|
class SnippetResult {
|
||||||
|
|||||||
@@ -1,179 +0,0 @@
|
|||||||
// dart format width=80
|
|
||||||
// coverage:ignore-file
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
|
||||||
|
|
||||||
part of 'snippet.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// dart format off
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$Snippet {
|
|
||||||
|
|
||||||
String get name; String get script; List<String>? get tags; String? get note;/// List of server id that this snippet should be auto run on
|
|
||||||
List<String>? get autoRunOn;
|
|
||||||
/// Create a copy of Snippet
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$SnippetCopyWith<Snippet> get copyWith => _$SnippetCopyWithImpl<Snippet>(this as Snippet, _$identity);
|
|
||||||
|
|
||||||
/// Serializes this Snippet to a JSON map.
|
|
||||||
Map<String, dynamic> toJson();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is Snippet&&(identical(other.name, name) || other.name == name)&&(identical(other.script, script) || other.script == script)&&const DeepCollectionEquality().equals(other.tags, tags)&&(identical(other.note, note) || other.note == note)&&const DeepCollectionEquality().equals(other.autoRunOn, autoRunOn));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,name,script,const DeepCollectionEquality().hash(tags),note,const DeepCollectionEquality().hash(autoRunOn));
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'Snippet(name: $name, script: $script, tags: $tags, note: $note, autoRunOn: $autoRunOn)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $SnippetCopyWith<$Res> {
|
|
||||||
factory $SnippetCopyWith(Snippet value, $Res Function(Snippet) _then) = _$SnippetCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
String name, String script, List<String>? tags, String? note, List<String>? autoRunOn
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$SnippetCopyWithImpl<$Res>
|
|
||||||
implements $SnippetCopyWith<$Res> {
|
|
||||||
_$SnippetCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final Snippet _self;
|
|
||||||
final $Res Function(Snippet) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Snippet
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? script = null,Object? tags = freezed,Object? note = freezed,Object? autoRunOn = freezed,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,script: null == script ? _self.script : script // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,tags: freezed == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
|
|
||||||
as List<String>?,note: freezed == note ? _self.note : note // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,autoRunOn: freezed == autoRunOn ? _self.autoRunOn : autoRunOn // ignore: cast_nullable_to_non_nullable
|
|
||||||
as List<String>?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@JsonSerializable()
|
|
||||||
|
|
||||||
class _Snippet implements Snippet {
|
|
||||||
const _Snippet({required this.name, required this.script, final List<String>? tags, this.note, final List<String>? autoRunOn}): _tags = tags,_autoRunOn = autoRunOn;
|
|
||||||
factory _Snippet.fromJson(Map<String, dynamic> json) => _$SnippetFromJson(json);
|
|
||||||
|
|
||||||
@override final String name;
|
|
||||||
@override final String script;
|
|
||||||
final List<String>? _tags;
|
|
||||||
@override List<String>? get tags {
|
|
||||||
final value = _tags;
|
|
||||||
if (value == null) return null;
|
|
||||||
if (_tags is EqualUnmodifiableListView) return _tags;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableListView(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override final String? note;
|
|
||||||
/// List of server id that this snippet should be auto run on
|
|
||||||
final List<String>? _autoRunOn;
|
|
||||||
/// List of server id that this snippet should be auto run on
|
|
||||||
@override List<String>? get autoRunOn {
|
|
||||||
final value = _autoRunOn;
|
|
||||||
if (value == null) return null;
|
|
||||||
if (_autoRunOn is EqualUnmodifiableListView) return _autoRunOn;
|
|
||||||
// ignore: implicit_dynamic_type
|
|
||||||
return EqualUnmodifiableListView(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Create a copy of Snippet
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$SnippetCopyWith<_Snippet> get copyWith => __$SnippetCopyWithImpl<_Snippet>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$SnippetToJson(this, );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Snippet&&(identical(other.name, name) || other.name == name)&&(identical(other.script, script) || other.script == script)&&const DeepCollectionEquality().equals(other._tags, _tags)&&(identical(other.note, note) || other.note == note)&&const DeepCollectionEquality().equals(other._autoRunOn, _autoRunOn));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,name,script,const DeepCollectionEquality().hash(_tags),note,const DeepCollectionEquality().hash(_autoRunOn));
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'Snippet(name: $name, script: $script, tags: $tags, note: $note, autoRunOn: $autoRunOn)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$SnippetCopyWith<$Res> implements $SnippetCopyWith<$Res> {
|
|
||||||
factory _$SnippetCopyWith(_Snippet value, $Res Function(_Snippet) _then) = __$SnippetCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
String name, String script, List<String>? tags, String? note, List<String>? autoRunOn
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$SnippetCopyWithImpl<$Res>
|
|
||||||
implements _$SnippetCopyWith<$Res> {
|
|
||||||
__$SnippetCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _Snippet _self;
|
|
||||||
final $Res Function(_Snippet) _then;
|
|
||||||
|
|
||||||
/// Create a copy of Snippet
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? script = null,Object? tags = freezed,Object? note = freezed,Object? autoRunOn = freezed,}) {
|
|
||||||
return _then(_Snippet(
|
|
||||||
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,script: null == script ? _self.script : script // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,tags: freezed == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
|
|
||||||
as List<String>?,note: freezed == note ? _self.note : note // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,autoRunOn: freezed == autoRunOn ? _self._autoRunOn : autoRunOn // ignore: cast_nullable_to_non_nullable
|
|
||||||
as List<String>?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// dart format on
|
|
||||||
@@ -2,24 +2,74 @@
|
|||||||
|
|
||||||
part of 'snippet.dart';
|
part of 'snippet.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class SnippetAdapter extends TypeAdapter<Snippet> {
|
||||||
|
@override
|
||||||
|
final int typeId = 2;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Snippet read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return Snippet(
|
||||||
|
name: fields[0] as String,
|
||||||
|
script: fields[1] as String,
|
||||||
|
tags: (fields[2] as List?)?.cast<String>(),
|
||||||
|
note: fields[3] as String?,
|
||||||
|
autoRunOn: (fields[4] as List?)?.cast<String>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, Snippet obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(5)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.name)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.script)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.tags)
|
||||||
|
..writeByte(3)
|
||||||
|
..write(obj.note)
|
||||||
|
..writeByte(4)
|
||||||
|
..write(obj.autoRunOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is SnippetAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
_Snippet _$SnippetFromJson(Map<String, dynamic> json) => _Snippet(
|
Snippet _$SnippetFromJson(Map<String, dynamic> json) => Snippet(
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
script: json['script'] as String,
|
script: json['script'] as String,
|
||||||
tags: (json['tags'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
tags: (json['tags'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||||
note: json['note'] as String?,
|
note: json['note'] as String?,
|
||||||
autoRunOn: (json['autoRunOn'] as List<dynamic>?)
|
autoRunOn: (json['autoRunOn'] as List<dynamic>?)
|
||||||
?.map((e) => e as String)
|
?.map((e) => e as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$SnippetToJson(_Snippet instance) => <String, dynamic>{
|
Map<String, dynamic> _$SnippetToJson(Snippet instance) => <String, dynamic>{
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'script': instance.script,
|
'script': instance.script,
|
||||||
'tags': instance.tags,
|
'tags': instance.tags,
|
||||||
'note': instance.note,
|
'note': instance.note,
|
||||||
'autoRunOn': instance.autoRunOn,
|
'autoRunOn': instance.autoRunOn,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:wake_on_lan/wake_on_lan.dart';
|
import 'package:wake_on_lan/wake_on_lan.dart';
|
||||||
|
|
||||||
part 'wol_cfg.g.dart';
|
part 'wol_cfg.g.dart';
|
||||||
|
|
||||||
@JsonSerializable(includeIfNull: false)
|
@JsonSerializable()
|
||||||
|
@HiveType(typeId: 8)
|
||||||
final class WakeOnLanCfg {
|
final class WakeOnLanCfg {
|
||||||
|
@HiveField(0)
|
||||||
final String mac;
|
final String mac;
|
||||||
|
@HiveField(1)
|
||||||
final String ip;
|
final String ip;
|
||||||
|
@HiveField(2)
|
||||||
final String? pwd;
|
final String? pwd;
|
||||||
|
|
||||||
const WakeOnLanCfg({
|
const WakeOnLanCfg({
|
||||||
@@ -21,12 +26,18 @@ final class WakeOnLanCfg {
|
|||||||
final macValidation = MACAddress.validate(mac);
|
final macValidation = MACAddress.validate(mac);
|
||||||
final ipValidation = IPAddress.validate(
|
final ipValidation = IPAddress.validate(
|
||||||
ip,
|
ip,
|
||||||
type: ip.contains(':') ? InternetAddressType.IPv6 : InternetAddressType.IPv4,
|
type: ip.contains(':')
|
||||||
|
? InternetAddressType.IPv6
|
||||||
|
: InternetAddressType.IPv4,
|
||||||
);
|
);
|
||||||
final pwdValidation = pwd != null ? SecureONPassword.validate(pwd) : (state: true, error: null);
|
final pwdValidation = pwd != null
|
||||||
|
? SecureONPassword.validate(pwd)
|
||||||
|
: (state: true, error: null);
|
||||||
|
|
||||||
final valid = macValidation.state && ipValidation.state && pwdValidation.state;
|
final valid =
|
||||||
final err = macValidation.error ?? ipValidation.error ?? pwdValidation.error;
|
macValidation.state && ipValidation.state && pwdValidation.state;
|
||||||
|
final err =
|
||||||
|
macValidation.error ?? ipValidation.error ?? pwdValidation.error;
|
||||||
return (err, valid);
|
return (err, valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +56,8 @@ final class WakeOnLanCfg {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory WakeOnLanCfg.fromJson(Map<String, dynamic> json) => _$WakeOnLanCfgFromJson(json);
|
factory WakeOnLanCfg.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$WakeOnLanCfgFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$WakeOnLanCfgToJson(this);
|
Map<String, dynamic> toJson() => _$WakeOnLanCfgToJson(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,63 @@
|
|||||||
|
|
||||||
part of 'wol_cfg.dart';
|
part of 'wol_cfg.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class WakeOnLanCfgAdapter extends TypeAdapter<WakeOnLanCfg> {
|
||||||
|
@override
|
||||||
|
final int typeId = 8;
|
||||||
|
|
||||||
|
@override
|
||||||
|
WakeOnLanCfg read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return WakeOnLanCfg(
|
||||||
|
mac: fields[0] as String,
|
||||||
|
ip: fields[1] as String,
|
||||||
|
pwd: fields[2] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, WakeOnLanCfg obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(3)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.mac)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.ip)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is WakeOnLanCfgAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
|
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
WakeOnLanCfg _$WakeOnLanCfgFromJson(Map<String, dynamic> json) => WakeOnLanCfg(
|
WakeOnLanCfg _$WakeOnLanCfgFromJson(Map<String, dynamic> json) => WakeOnLanCfg(
|
||||||
mac: json['mac'] as String,
|
mac: json['mac'] as String,
|
||||||
ip: json['ip'] as String,
|
ip: json['ip'] as String,
|
||||||
pwd: json['pwd'] as String?,
|
pwd: json['pwd'] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$WakeOnLanCfgToJson(WakeOnLanCfg instance) =>
|
Map<String, dynamic> _$WakeOnLanCfgToJson(WakeOnLanCfg instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'mac': instance.mac,
|
'mac': instance.mac,
|
||||||
'ip': instance.ip,
|
'ip': instance.ip,
|
||||||
if (instance.pwd case final value?) 'pwd': value,
|
'pwd': instance.pwd,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class _AbsolutePath {
|
|||||||
_path = newPath;
|
_path = newPath;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_path = _path.joinPath(newPath, separator: _sep);
|
_path = _path.joinPath(newPath, seperator: _sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool undo() {
|
bool undo() {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SftpReq {
|
|||||||
}
|
}
|
||||||
if (spi.jumpId != null) {
|
if (spi.jumpId != null) {
|
||||||
jumpSpi = Stores.server.box.get(spi.jumpId);
|
jumpSpi = Stores.server.box.get(spi.jumpId);
|
||||||
jumpPrivateKey = Stores.key.fetchOne(jumpSpi?.keyId)?.key;
|
jumpPrivateKey = Stores.key.get(jumpSpi?.keyId)?.key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ Future<void> isolateMessageHandler(
|
|||||||
case SftpReqType.upload:
|
case SftpReqType.upload:
|
||||||
await _upload(data, mainSendPort, sendError);
|
await _upload(data, mainSendPort, sendError);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
sendError(Exception('unknown type'));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,56 +1,81 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
import 'package:server_box/data/res/store.dart';
|
import 'package:server_box/data/res/store.dart';
|
||||||
import 'package:xterm/core.dart';
|
import 'package:xterm/core.dart';
|
||||||
|
|
||||||
|
part 'virtual_key.g.dart';
|
||||||
|
|
||||||
enum VirtualKeyFunc { toggleIME, backspace, clipboard, snippet, file }
|
enum VirtualKeyFunc { toggleIME, backspace, clipboard, snippet, file }
|
||||||
|
|
||||||
|
@HiveType(typeId: 4)
|
||||||
enum VirtKey {
|
enum VirtKey {
|
||||||
|
@HiveField(0)
|
||||||
esc,
|
esc,
|
||||||
|
@HiveField(1)
|
||||||
alt,
|
alt,
|
||||||
|
@HiveField(2)
|
||||||
home,
|
home,
|
||||||
|
@HiveField(3)
|
||||||
up,
|
up,
|
||||||
|
@HiveField(4)
|
||||||
end,
|
end,
|
||||||
|
@HiveField(5)
|
||||||
sftp,
|
sftp,
|
||||||
|
@HiveField(6)
|
||||||
snippet,
|
snippet,
|
||||||
|
@HiveField(7)
|
||||||
tab,
|
tab,
|
||||||
|
@HiveField(8)
|
||||||
ctrl,
|
ctrl,
|
||||||
|
@HiveField(9)
|
||||||
left,
|
left,
|
||||||
|
@HiveField(10)
|
||||||
down,
|
down,
|
||||||
|
@HiveField(11)
|
||||||
right,
|
right,
|
||||||
|
@HiveField(12)
|
||||||
clipboard,
|
clipboard,
|
||||||
|
@HiveField(13)
|
||||||
ime,
|
ime,
|
||||||
|
@HiveField(14)
|
||||||
pgup,
|
pgup,
|
||||||
|
@HiveField(15)
|
||||||
pgdn,
|
pgdn,
|
||||||
|
@HiveField(16)
|
||||||
slash,
|
slash,
|
||||||
|
@HiveField(17)
|
||||||
backSlash,
|
backSlash,
|
||||||
|
@HiveField(18)
|
||||||
underscore,
|
underscore,
|
||||||
|
@HiveField(19)
|
||||||
plus,
|
plus,
|
||||||
|
@HiveField(20)
|
||||||
equal,
|
equal,
|
||||||
|
@HiveField(21)
|
||||||
minus,
|
minus,
|
||||||
|
@HiveField(22)
|
||||||
parenLeft,
|
parenLeft,
|
||||||
|
@HiveField(23)
|
||||||
parenRight,
|
parenRight,
|
||||||
|
@HiveField(24)
|
||||||
bracketLeft,
|
bracketLeft,
|
||||||
|
@HiveField(25)
|
||||||
bracketRight,
|
bracketRight,
|
||||||
|
@HiveField(26)
|
||||||
braceLeft,
|
braceLeft,
|
||||||
|
@HiveField(27)
|
||||||
braceRight,
|
braceRight,
|
||||||
|
@HiveField(28)
|
||||||
chevronLeft,
|
chevronLeft,
|
||||||
|
@HiveField(29)
|
||||||
chevronRight,
|
chevronRight,
|
||||||
|
@HiveField(30)
|
||||||
colon,
|
colon,
|
||||||
|
@HiveField(31)
|
||||||
semicolon,
|
semicolon,
|
||||||
f1,
|
;
|
||||||
f2,
|
|
||||||
f3,
|
|
||||||
f4,
|
|
||||||
f5,
|
|
||||||
f6,
|
|
||||||
f7,
|
|
||||||
f8,
|
|
||||||
f9,
|
|
||||||
f10,
|
|
||||||
f11,
|
|
||||||
f12;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VirtKeyX on VirtKey {
|
extension VirtKeyX on VirtKey {
|
||||||
@@ -121,18 +146,6 @@ extension VirtKeyX on VirtKey {
|
|||||||
VirtKey.right => TerminalKey.arrowRight,
|
VirtKey.right => TerminalKey.arrowRight,
|
||||||
VirtKey.pgup => TerminalKey.pageUp,
|
VirtKey.pgup => TerminalKey.pageUp,
|
||||||
VirtKey.pgdn => TerminalKey.pageDown,
|
VirtKey.pgdn => TerminalKey.pageDown,
|
||||||
VirtKey.f1 => TerminalKey.f1,
|
|
||||||
VirtKey.f2 => TerminalKey.f2,
|
|
||||||
VirtKey.f3 => TerminalKey.f3,
|
|
||||||
VirtKey.f4 => TerminalKey.f4,
|
|
||||||
VirtKey.f5 => TerminalKey.f5,
|
|
||||||
VirtKey.f6 => TerminalKey.f6,
|
|
||||||
VirtKey.f7 => TerminalKey.f7,
|
|
||||||
VirtKey.f8 => TerminalKey.f8,
|
|
||||||
VirtKey.f9 => TerminalKey.f9,
|
|
||||||
VirtKey.f10 => TerminalKey.f10,
|
|
||||||
VirtKey.f11 => TerminalKey.f11,
|
|
||||||
VirtKey.f12 => TerminalKey.f12,
|
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
196
lib/data/model/ssh/virtual_key.g.dart
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'virtual_key.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class VirtKeyAdapter extends TypeAdapter<VirtKey> {
|
||||||
|
@override
|
||||||
|
final int typeId = 4;
|
||||||
|
|
||||||
|
@override
|
||||||
|
VirtKey read(BinaryReader reader) {
|
||||||
|
switch (reader.readByte()) {
|
||||||
|
case 0:
|
||||||
|
return VirtKey.esc;
|
||||||
|
case 1:
|
||||||
|
return VirtKey.alt;
|
||||||
|
case 2:
|
||||||
|
return VirtKey.home;
|
||||||
|
case 3:
|
||||||
|
return VirtKey.up;
|
||||||
|
case 4:
|
||||||
|
return VirtKey.end;
|
||||||
|
case 5:
|
||||||
|
return VirtKey.sftp;
|
||||||
|
case 6:
|
||||||
|
return VirtKey.snippet;
|
||||||
|
case 7:
|
||||||
|
return VirtKey.tab;
|
||||||
|
case 8:
|
||||||
|
return VirtKey.ctrl;
|
||||||
|
case 9:
|
||||||
|
return VirtKey.left;
|
||||||
|
case 10:
|
||||||
|
return VirtKey.down;
|
||||||
|
case 11:
|
||||||
|
return VirtKey.right;
|
||||||
|
case 12:
|
||||||
|
return VirtKey.clipboard;
|
||||||
|
case 13:
|
||||||
|
return VirtKey.ime;
|
||||||
|
case 14:
|
||||||
|
return VirtKey.pgup;
|
||||||
|
case 15:
|
||||||
|
return VirtKey.pgdn;
|
||||||
|
case 16:
|
||||||
|
return VirtKey.slash;
|
||||||
|
case 17:
|
||||||
|
return VirtKey.backSlash;
|
||||||
|
case 18:
|
||||||
|
return VirtKey.underscore;
|
||||||
|
case 19:
|
||||||
|
return VirtKey.plus;
|
||||||
|
case 20:
|
||||||
|
return VirtKey.equal;
|
||||||
|
case 21:
|
||||||
|
return VirtKey.minus;
|
||||||
|
case 22:
|
||||||
|
return VirtKey.parenLeft;
|
||||||
|
case 23:
|
||||||
|
return VirtKey.parenRight;
|
||||||
|
case 24:
|
||||||
|
return VirtKey.bracketLeft;
|
||||||
|
case 25:
|
||||||
|
return VirtKey.bracketRight;
|
||||||
|
case 26:
|
||||||
|
return VirtKey.braceLeft;
|
||||||
|
case 27:
|
||||||
|
return VirtKey.braceRight;
|
||||||
|
case 28:
|
||||||
|
return VirtKey.chevronLeft;
|
||||||
|
case 29:
|
||||||
|
return VirtKey.chevronRight;
|
||||||
|
case 30:
|
||||||
|
return VirtKey.colon;
|
||||||
|
case 31:
|
||||||
|
return VirtKey.semicolon;
|
||||||
|
default:
|
||||||
|
return VirtKey.esc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, VirtKey obj) {
|
||||||
|
switch (obj) {
|
||||||
|
case VirtKey.esc:
|
||||||
|
writer.writeByte(0);
|
||||||
|
break;
|
||||||
|
case VirtKey.alt:
|
||||||
|
writer.writeByte(1);
|
||||||
|
break;
|
||||||
|
case VirtKey.home:
|
||||||
|
writer.writeByte(2);
|
||||||
|
break;
|
||||||
|
case VirtKey.up:
|
||||||
|
writer.writeByte(3);
|
||||||
|
break;
|
||||||
|
case VirtKey.end:
|
||||||
|
writer.writeByte(4);
|
||||||
|
break;
|
||||||
|
case VirtKey.sftp:
|
||||||
|
writer.writeByte(5);
|
||||||
|
break;
|
||||||
|
case VirtKey.snippet:
|
||||||
|
writer.writeByte(6);
|
||||||
|
break;
|
||||||
|
case VirtKey.tab:
|
||||||
|
writer.writeByte(7);
|
||||||
|
break;
|
||||||
|
case VirtKey.ctrl:
|
||||||
|
writer.writeByte(8);
|
||||||
|
break;
|
||||||
|
case VirtKey.left:
|
||||||
|
writer.writeByte(9);
|
||||||
|
break;
|
||||||
|
case VirtKey.down:
|
||||||
|
writer.writeByte(10);
|
||||||
|
break;
|
||||||
|
case VirtKey.right:
|
||||||
|
writer.writeByte(11);
|
||||||
|
break;
|
||||||
|
case VirtKey.clipboard:
|
||||||
|
writer.writeByte(12);
|
||||||
|
break;
|
||||||
|
case VirtKey.ime:
|
||||||
|
writer.writeByte(13);
|
||||||
|
break;
|
||||||
|
case VirtKey.pgup:
|
||||||
|
writer.writeByte(14);
|
||||||
|
break;
|
||||||
|
case VirtKey.pgdn:
|
||||||
|
writer.writeByte(15);
|
||||||
|
break;
|
||||||
|
case VirtKey.slash:
|
||||||
|
writer.writeByte(16);
|
||||||
|
break;
|
||||||
|
case VirtKey.backSlash:
|
||||||
|
writer.writeByte(17);
|
||||||
|
break;
|
||||||
|
case VirtKey.underscore:
|
||||||
|
writer.writeByte(18);
|
||||||
|
break;
|
||||||
|
case VirtKey.plus:
|
||||||
|
writer.writeByte(19);
|
||||||
|
break;
|
||||||
|
case VirtKey.equal:
|
||||||
|
writer.writeByte(20);
|
||||||
|
break;
|
||||||
|
case VirtKey.minus:
|
||||||
|
writer.writeByte(21);
|
||||||
|
break;
|
||||||
|
case VirtKey.parenLeft:
|
||||||
|
writer.writeByte(22);
|
||||||
|
break;
|
||||||
|
case VirtKey.parenRight:
|
||||||
|
writer.writeByte(23);
|
||||||
|
break;
|
||||||
|
case VirtKey.bracketLeft:
|
||||||
|
writer.writeByte(24);
|
||||||
|
break;
|
||||||
|
case VirtKey.bracketRight:
|
||||||
|
writer.writeByte(25);
|
||||||
|
break;
|
||||||
|
case VirtKey.braceLeft:
|
||||||
|
writer.writeByte(26);
|
||||||
|
break;
|
||||||
|
case VirtKey.braceRight:
|
||||||
|
writer.writeByte(27);
|
||||||
|
break;
|
||||||
|
case VirtKey.chevronLeft:
|
||||||
|
writer.writeByte(28);
|
||||||
|
break;
|
||||||
|
case VirtKey.chevronRight:
|
||||||
|
writer.writeByte(29);
|
||||||
|
break;
|
||||||
|
case VirtKey.colon:
|
||||||
|
writer.writeByte(30);
|
||||||
|
break;
|
||||||
|
case VirtKey.semicolon:
|
||||||
|
writer.writeByte(31);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is VirtKeyAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
@@ -1,27 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
||||||
|
|
||||||
part 'app.g.dart';
|
final class AppProvider {
|
||||||
part 'app.freezed.dart';
|
const AppProvider._();
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class AppState with _$AppState {
|
|
||||||
const factory AppState({
|
|
||||||
@Default(false) bool desktopMode,
|
|
||||||
}) = _AppState;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
|
||||||
class AppProvider extends _$AppProvider {
|
|
||||||
static BuildContext? ctx;
|
static BuildContext? ctx;
|
||||||
|
|
||||||
@override
|
|
||||||
AppState build() {
|
|
||||||
return const AppState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDesktop(bool desktopMode) {
|
|
||||||
state = state.copyWith(desktopMode: desktopMode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,142 +0,0 @@
|
|||||||
// dart format width=80
|
|
||||||
// coverage:ignore-file
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
|
||||||
|
|
||||||
part of 'app.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// dart format off
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$AppState {
|
|
||||||
|
|
||||||
bool get desktopMode;
|
|
||||||
/// Create a copy of AppState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$AppStateCopyWith<AppState> get copyWith => _$AppStateCopyWithImpl<AppState>(this as AppState, _$identity);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppState&&(identical(other.desktopMode, desktopMode) || other.desktopMode == desktopMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,desktopMode);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'AppState(desktopMode: $desktopMode)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $AppStateCopyWith<$Res> {
|
|
||||||
factory $AppStateCopyWith(AppState value, $Res Function(AppState) _then) = _$AppStateCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
bool desktopMode
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$AppStateCopyWithImpl<$Res>
|
|
||||||
implements $AppStateCopyWith<$Res> {
|
|
||||||
_$AppStateCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final AppState _self;
|
|
||||||
final $Res Function(AppState) _then;
|
|
||||||
|
|
||||||
/// Create a copy of AppState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? desktopMode = null,}) {
|
|
||||||
return _then(_self.copyWith(
|
|
||||||
desktopMode: null == desktopMode ? _self.desktopMode : desktopMode // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
|
|
||||||
class _AppState implements AppState {
|
|
||||||
const _AppState({this.desktopMode = false});
|
|
||||||
|
|
||||||
|
|
||||||
@override@JsonKey() final bool desktopMode;
|
|
||||||
|
|
||||||
/// Create a copy of AppState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$AppStateCopyWith<_AppState> get copyWith => __$AppStateCopyWithImpl<_AppState>(this, _$identity);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppState&&(identical(other.desktopMode, desktopMode) || other.desktopMode == desktopMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,desktopMode);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'AppState(desktopMode: $desktopMode)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class _$AppStateCopyWith<$Res> implements $AppStateCopyWith<$Res> {
|
|
||||||
factory _$AppStateCopyWith(_AppState value, $Res Function(_AppState) _then) = __$AppStateCopyWithImpl;
|
|
||||||
@override @useResult
|
|
||||||
$Res call({
|
|
||||||
bool desktopMode
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class __$AppStateCopyWithImpl<$Res>
|
|
||||||
implements _$AppStateCopyWith<$Res> {
|
|
||||||
__$AppStateCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final _AppState _self;
|
|
||||||
final $Res Function(_AppState) _then;
|
|
||||||
|
|
||||||
/// Create a copy of AppState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? desktopMode = null,}) {
|
|
||||||
return _then(_AppState(
|
|
||||||
desktopMode: null == desktopMode ? _self.desktopMode : desktopMode // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// dart format on
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'app.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// RiverpodGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
String _$appProviderHash() => r'8378ec9d0a9c8d99cc05805047cd2d52ac4dbb56';
|
|
||||||
|
|
||||||
/// See also [AppProvider].
|
|
||||||
@ProviderFor(AppProvider)
|
|
||||||
final appProviderProvider = NotifierProvider<AppProvider, AppState>.internal(
|
|
||||||
AppProvider.new,
|
|
||||||
name: r'appProviderProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$appProviderHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef _$AppProvider = Notifier<AppState>;
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
|
||||||
@@ -5,10 +5,10 @@ import 'package:dartssh2/dartssh2.dart';
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:server_box/core/extension/ssh_client.dart';
|
import 'package:server_box/core/extension/ssh_client.dart';
|
||||||
import 'package:server_box/data/model/app/error.dart';
|
|
||||||
import 'package:server_box/data/model/app/shell_func.dart';
|
import 'package:server_box/data/model/app/shell_func.dart';
|
||||||
import 'package:server_box/data/model/container/image.dart';
|
import 'package:server_box/data/model/container/image.dart';
|
||||||
import 'package:server_box/data/model/container/ps.dart';
|
import 'package:server_box/data/model/container/ps.dart';
|
||||||
|
import 'package:server_box/data/model/app/error.dart';
|
||||||
import 'package:server_box/data/model/container/type.dart';
|
import 'package:server_box/data/model/container/type.dart';
|
||||||
import 'package:server_box/data/res/store.dart';
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
|
||||||
@@ -222,23 +222,6 @@ class ContainerProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<ContainerErr?> restart(String id) async => await run('restart $id');
|
Future<ContainerErr?> restart(String id) async => await run('restart $id');
|
||||||
|
|
||||||
Future<ContainerErr?> pruneImages({bool all = true}) async {
|
|
||||||
final cmd = 'image prune${all ? " -a" : ""} -f';
|
|
||||||
return await run(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ContainerErr?> pruneContainers() async {
|
|
||||||
return await run('container prune -f');
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ContainerErr?> pruneVolumes() async {
|
|
||||||
return await run('volume prune -f');
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ContainerErr?> pruneSystem() async {
|
|
||||||
return await run('system prune -a -f --volumes');
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ContainerErr?> run(String cmd, {bool autoRefresh = true}) async {
|
Future<ContainerErr?> run(String cmd, {bool autoRefresh = true}) async {
|
||||||
cmd = switch (type) {
|
cmd = switch (type) {
|
||||||
ContainerType.docker => 'docker $cmd',
|
ContainerType.docker => 'docker $cmd',
|
||||||
@@ -289,8 +272,6 @@ enum ContainerCmdType {
|
|||||||
ps,
|
ps,
|
||||||
stats,
|
stats,
|
||||||
images,
|
images,
|
||||||
// No specific commands needed for prune actions as they are simple
|
|
||||||
// and don't require splitting output with ShellFunc.seperator
|
|
||||||
;
|
;
|
||||||
|
|
||||||
String exec(
|
String exec(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dio/io.dart';
|
import 'package:dio/io.dart';
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
@@ -11,6 +10,7 @@ import 'package:server_box/core/extension/context/locale.dart';
|
|||||||
import 'package:server_box/data/model/app/error.dart';
|
import 'package:server_box/data/model/app/error.dart';
|
||||||
import 'package:server_box/data/model/server/pve.dart';
|
import 'package:server_box/data/model/server/pve.dart';
|
||||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||||
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
|
|
||||||
typedef PveCtrlFunc = Future<bool> Function(String node, String id);
|
typedef PveCtrlFunc = Future<bool> Function(String node, String id);
|
||||||
|
|
||||||
@@ -47,11 +47,11 @@ final class PveProvider extends ChangeNotifier {
|
|||||||
final client = HttpClient();
|
final client = HttpClient();
|
||||||
client.connectionFactory = cf;
|
client.connectionFactory = cf;
|
||||||
if (_ignoreCert) {
|
if (_ignoreCert) {
|
||||||
client.badCertificateCallback = (_, _, _) => true;
|
client.badCertificateCallback = (_, __, ___) => true;
|
||||||
}
|
}
|
||||||
return client;
|
return client;
|
||||||
},
|
},
|
||||||
validateCertificate: _ignoreCert ? (_, _, _) => true : null,
|
validateCertificate: _ignoreCert ? (_, __, ___) => true : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
final data = ValueNotifier<PveRes?>(null);
|
final data = ValueNotifier<PveRes?>(null);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
// import 'dart:io';
|
// import 'dart:io';
|
||||||
|
|
||||||
import 'package:computer/computer.dart';
|
import 'package:computer/computer.dart';
|
||||||
@@ -7,17 +6,18 @@ import 'package:dartssh2/dartssh2.dart';
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:server_box/core/extension/ssh_client.dart';
|
import 'package:server_box/core/extension/ssh_client.dart';
|
||||||
import 'package:server_box/core/sync.dart';
|
import 'package:server_box/core/sync.dart';
|
||||||
import 'package:server_box/core/utils/server.dart';
|
|
||||||
import 'package:server_box/core/utils/ssh_auth.dart';
|
import 'package:server_box/core/utils/ssh_auth.dart';
|
||||||
import 'package:server_box/data/model/app/error.dart';
|
import 'package:server_box/data/model/app/error.dart';
|
||||||
import 'package:server_box/data/model/app/shell_func.dart';
|
import 'package:server_box/data/model/app/shell_func.dart';
|
||||||
|
import 'package:server_box/data/model/server/system.dart';
|
||||||
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
|
||||||
|
import 'package:server_box/core/utils/server.dart';
|
||||||
import 'package:server_box/data/model/server/server.dart';
|
import 'package:server_box/data/model/server/server.dart';
|
||||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||||
import 'package:server_box/data/model/server/server_status_update_req.dart';
|
import 'package:server_box/data/model/server/server_status_update_req.dart';
|
||||||
import 'package:server_box/data/model/server/system.dart';
|
|
||||||
import 'package:server_box/data/model/server/try_limiter.dart';
|
import 'package:server_box/data/model/server/try_limiter.dart';
|
||||||
import 'package:server_box/data/res/status.dart';
|
import 'package:server_box/data/res/status.dart';
|
||||||
import 'package:server_box/data/res/store.dart';
|
|
||||||
|
|
||||||
class ServerProvider extends Provider {
|
class ServerProvider extends Provider {
|
||||||
const ServerProvider._();
|
const ServerProvider._();
|
||||||
@@ -45,20 +45,22 @@ class ServerProvider extends Provider {
|
|||||||
for (int idx = 0; idx < spis.length; idx++) {
|
for (int idx = 0; idx < spis.length; idx++) {
|
||||||
final spi = spis[idx];
|
final spi = spis[idx];
|
||||||
final originServer = oldServers[spi.id];
|
final originServer = oldServers[spi.id];
|
||||||
|
final newServer = genServer(spi);
|
||||||
|
|
||||||
/// #258
|
/// #258
|
||||||
/// If not [shouldReconnect], then keep the old state.
|
/// If not [shouldReconnect], then keep the old state.
|
||||||
if (originServer != null && !originServer.value.spi.shouldReconnect(spi)) {
|
if (originServer != null &&
|
||||||
originServer.value.spi = spi;
|
!originServer.value.spi.shouldReconnect(spi)) {
|
||||||
servers[spi.id] = originServer;
|
newServer.conn = originServer.value.conn;
|
||||||
} else {
|
|
||||||
final newServer = genServer(spi);
|
|
||||||
servers[spi.id] = newServer.vn;
|
|
||||||
}
|
}
|
||||||
|
servers[spi.id] = newServer.vn;
|
||||||
}
|
}
|
||||||
final serverOrder_ = Stores.setting.serverOrder.fetch();
|
final serverOrder_ = Stores.setting.serverOrder.fetch();
|
||||||
if (serverOrder_.isNotEmpty) {
|
if (serverOrder_.isNotEmpty) {
|
||||||
spis.reorder(order: serverOrder_, finder: (n, id) => n.id == id);
|
spis.reorder(
|
||||||
|
order: serverOrder_,
|
||||||
|
finder: (n, id) => n.id == id,
|
||||||
|
);
|
||||||
serverOrder.value.addAll(spis.map((e) => e.id));
|
serverOrder.value.addAll(spis.map((e) => e.id));
|
||||||
} else {
|
} else {
|
||||||
serverOrder.value.addAll(servers.keys);
|
serverOrder.value.addAll(servers.keys);
|
||||||
@@ -103,30 +105,31 @@ class ServerProvider extends Provider {
|
|||||||
|
|
||||||
/// if [spi] is specificed then only refresh this server
|
/// if [spi] is specificed then only refresh this server
|
||||||
/// [onlyFailed] only refresh failed servers
|
/// [onlyFailed] only refresh failed servers
|
||||||
static Future<void> refresh({Spi? spi, bool onlyFailed = false}) async {
|
static Future<void> refresh({
|
||||||
|
Spi? spi,
|
||||||
|
bool onlyFailed = false,
|
||||||
|
}) async {
|
||||||
if (spi != null) {
|
if (spi != null) {
|
||||||
_manualDisconnectedIds.remove(spi.id);
|
_manualDisconnectedIds.remove(spi.id);
|
||||||
await _getData(spi);
|
await _getData(spi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Future.wait(
|
await Future.wait(servers.values.map((val) async {
|
||||||
servers.values.map((val) async {
|
final s = val.value;
|
||||||
final s = val.value;
|
if (onlyFailed) {
|
||||||
if (onlyFailed) {
|
if (s.conn != ServerConn.failed) return;
|
||||||
if (s.conn != ServerConn.failed) return;
|
TryLimiter.reset(s.spi.id);
|
||||||
TryLimiter.reset(s.spi.id);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_manualDisconnectedIds.contains(s.spi.id)) return;
|
if (_manualDisconnectedIds.contains(s.spi.id)) return;
|
||||||
|
|
||||||
if (s.conn == ServerConn.disconnected && !s.spi.autoConnect) {
|
if (s.conn == ServerConn.disconnected && !s.spi.autoConnect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _getData(s.spi);
|
return await _getData(s.spi);
|
||||||
}),
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> startAutoRefresh() async {
|
static Future<void> startAutoRefresh() async {
|
||||||
@@ -171,16 +174,12 @@ class ServerProvider extends Provider {
|
|||||||
|
|
||||||
static void _closeOneServer(String id) {
|
static void _closeOneServer(String id) {
|
||||||
final s = servers[id];
|
final s = servers[id];
|
||||||
if (s == null) {
|
final item = s?.value;
|
||||||
Loggers.app.warning('Server with id $id not found');
|
item?.client?.close();
|
||||||
return;
|
item?.client = null;
|
||||||
}
|
item?.conn = ServerConn.disconnected;
|
||||||
final item = s.value;
|
|
||||||
item.client?.close();
|
|
||||||
item.client = null;
|
|
||||||
item.conn = ServerConn.disconnected;
|
|
||||||
_manualDisconnectedIds.add(id);
|
_manualDisconnectedIds.add(id);
|
||||||
s.notify();
|
s?.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addServer(Spi spi) {
|
static void addServer(Spi spi) {
|
||||||
@@ -209,12 +208,14 @@ class ServerProvider extends Provider {
|
|||||||
serverOrder.value.clear();
|
serverOrder.value.clear();
|
||||||
serverOrder.notify();
|
serverOrder.notify();
|
||||||
Stores.setting.serverOrder.put(serverOrder.value);
|
Stores.setting.serverOrder.put(serverOrder.value);
|
||||||
Stores.server.clear();
|
Stores.server.deleteAll();
|
||||||
_updateTags();
|
_updateTags();
|
||||||
bakSync.sync(milliDelay: 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> updateServer(Spi old, Spi newSpi) async {
|
static Future<void> updateServer(
|
||||||
|
Spi old,
|
||||||
|
Spi newSpi,
|
||||||
|
) async {
|
||||||
if (old != newSpi) {
|
if (old != newSpi) {
|
||||||
Stores.server.update(old, newSpi);
|
Stores.server.update(old, newSpi);
|
||||||
servers[old.id]?.value.spi = newSpi;
|
servers[old.id]?.value.spi = newSpi;
|
||||||
@@ -235,7 +236,7 @@ class ServerProvider extends Provider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_updateTags();
|
_updateTags();
|
||||||
bakSync.sync(milliDelay: 1000);
|
bakSync.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _setServerState(VNode<Server> s, ServerConn ss) {
|
static void _setServerState(VNode<Server> s, ServerConn ss) {
|
||||||
@@ -305,11 +306,14 @@ class ServerProvider extends Provider {
|
|||||||
_setServerState(s, ServerConn.connected);
|
_setServerState(s, ServerConn.connected);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final (_, writeScriptResult) = await sv.client!.exec((session) async {
|
final (_, writeScriptResult) = await sv.client!.exec(
|
||||||
final scriptRaw = ShellFunc.allScript(spi.custom?.cmds).uint8List;
|
(session) async {
|
||||||
session.stdin.add(scriptRaw);
|
final scriptRaw = ShellFunc.allScript(spi.custom?.cmds).uint8List;
|
||||||
session.stdin.close();
|
session.stdin.add(scriptRaw);
|
||||||
}, entry: ShellFunc.getInstallShellCmd(spi.id));
|
session.stdin.close();
|
||||||
|
},
|
||||||
|
entry: ShellFunc.getInstallShellCmd(spi.id),
|
||||||
|
);
|
||||||
if (writeScriptResult.isNotEmpty) {
|
if (writeScriptResult.isNotEmpty) {
|
||||||
ShellFunc.switchScriptDir(spi.id);
|
ShellFunc.switchScriptDir(spi.id);
|
||||||
throw writeScriptResult;
|
throw writeScriptResult;
|
||||||
@@ -361,7 +365,10 @@ class ServerProvider extends Provider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TryLimiter.inc(sid);
|
TryLimiter.inc(sid);
|
||||||
sv.status.err = SSHErr(type: SSHErrType.segements, message: 'Seperate segments failed, raw:\n$raw');
|
sv.status.err = SSHErr(
|
||||||
|
type: SSHErrType.segements,
|
||||||
|
message: 'Seperate segments failed, raw:\n$raw',
|
||||||
|
);
|
||||||
_setServerState(s, ServerConn.failed);
|
_setServerState(s, ServerConn.failed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -400,10 +407,17 @@ class ServerProvider extends Provider {
|
|||||||
system: systemType,
|
system: systemType,
|
||||||
customCmds: spi.custom?.cmds ?? {},
|
customCmds: spi.custom?.cmds ?? {},
|
||||||
);
|
);
|
||||||
sv.status = await Computer.shared.start(getStatus, req, taskName: 'StatusUpdateReq<${sv.id}>');
|
sv.status = await Computer.shared.start(
|
||||||
|
getStatus,
|
||||||
|
req,
|
||||||
|
taskName: 'StatusUpdateReq<${sv.id}>',
|
||||||
|
);
|
||||||
} catch (e, trace) {
|
} catch (e, trace) {
|
||||||
TryLimiter.inc(sid);
|
TryLimiter.inc(sid);
|
||||||
sv.status.err = SSHErr(type: SSHErrType.getStatus, message: 'Parse failed: $e\n\n$raw');
|
sv.status.err = SSHErr(
|
||||||
|
type: SSHErrType.getStatus,
|
||||||
|
message: 'Parse failed: $e\n\n$raw',
|
||||||
|
);
|
||||||
_setServerState(s, ServerConn.failed);
|
_setServerState(s, ServerConn.failed);
|
||||||
Loggers.app.warning('Server status', e, trace);
|
Loggers.app.warning('Server status', e, trace);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ class SftpProvider extends Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int add(SftpReq req, {Completer? completer}) {
|
static int add(SftpReq req, {Completer? completer}) {
|
||||||
final reqStat = SftpReqStatus(notifyListeners: status.notify, completer: completer, req: req);
|
final reqStat = SftpReqStatus(
|
||||||
|
notifyListeners: status.notify,
|
||||||
|
completer: completer,
|
||||||
|
req: req,
|
||||||
|
);
|
||||||
status.value.add(reqStat);
|
status.value.add(reqStat);
|
||||||
status.notify();
|
status.notify();
|
||||||
return reqStat.id;
|
return reqStat.id;
|
||||||
@@ -30,10 +34,6 @@ class SftpProvider extends Provider {
|
|||||||
|
|
||||||
static void cancel(int id) {
|
static void cancel(int id) {
|
||||||
final idx = status.value.indexWhere((e) => e.id == id);
|
final idx = status.value.indexWhere((e) => e.id == id);
|
||||||
if (idx < 0 || idx >= status.value.length) {
|
|
||||||
dprint('SftpProvider.cancel: id $id not found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
status.value[idx].dispose();
|
status.value[idx].dispose();
|
||||||
status.value.removeAt(idx);
|
status.value.removeAt(idx);
|
||||||
status.notify();
|
status.notify();
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
|
|
||||||
abstract class BuildData {
|
abstract class BuildData {
|
||||||
static const String name = "ServerBox";
|
static const String name = "ServerBox";
|
||||||
static const int build = 1189;
|
static const int build = 1104;
|
||||||
static const int script = 64;
|
static const int script = 58;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,6 @@ abstract final class GithubIds {
|
|||||||
'dccif',
|
'dccif',
|
||||||
'mikropsoft',
|
'mikropsoft',
|
||||||
'CakesTwix',
|
'CakesTwix',
|
||||||
'dsvf',
|
|
||||||
'fei1025',
|
|
||||||
'MasedMSD',
|
|
||||||
'GitGitro',
|
|
||||||
'Shin-suechtig',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const participants = <GhId>{
|
static const participants = <GhId>{
|
||||||
@@ -104,20 +99,6 @@ abstract final class GithubIds {
|
|||||||
'88484396',
|
'88484396',
|
||||||
'honggeigei',
|
'honggeigei',
|
||||||
'likecreep',
|
'likecreep',
|
||||||
'axlrose',
|
|
||||||
'immortal521',
|
|
||||||
'PRO-2684',
|
|
||||||
'Xiaobao-Yang',
|
|
||||||
'Mrhs121',
|
|
||||||
'Fudiautobi',
|
|
||||||
'papaj-na-wrotkach',
|
|
||||||
'kid1412621',
|
|
||||||
'smanx',
|
|
||||||
'xuanyue1024',
|
|
||||||
'RuofengX',
|
|
||||||
'rhwong',
|
|
||||||
'AstroEngineeer',
|
|
||||||
'mochasweet',
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
lib/data/res/rebuild.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
|
abstract final class RNodes {
|
||||||
|
static final app = RNode();
|
||||||
|
static final dark = false.vn;
|
||||||
|
}
|
||||||
@@ -1,40 +1,64 @@
|
|||||||
import 'package:server_box/data/model/server/conn.dart';
|
import 'package:server_box/data/model/server/server.dart';
|
||||||
|
import 'package:server_box/data/model/server/temp.dart';
|
||||||
|
|
||||||
import 'package:server_box/data/model/server/cpu.dart';
|
import 'package:server_box/data/model/server/cpu.dart';
|
||||||
import 'package:server_box/data/model/server/disk.dart';
|
import 'package:server_box/data/model/server/disk.dart';
|
||||||
import 'package:server_box/data/model/server/memory.dart';
|
import 'package:server_box/data/model/server/memory.dart';
|
||||||
import 'package:server_box/data/model/server/net_speed.dart';
|
import 'package:server_box/data/model/server/net_speed.dart';
|
||||||
import 'package:server_box/data/model/server/server.dart';
|
import 'package:server_box/data/model/server/conn.dart';
|
||||||
import 'package:server_box/data/model/server/system.dart';
|
import 'package:server_box/data/model/server/system.dart';
|
||||||
import 'package:server_box/data/model/server/temp.dart';
|
|
||||||
|
|
||||||
abstract final class InitStatus {
|
abstract final class InitStatus {
|
||||||
static SingleCpuCore get _initOneTimeCpuStatus =>
|
static SingleCpuCore get _initOneTimeCpuStatus => SingleCpuCore(
|
||||||
SingleCpuCore('cpu', 0, 0, 0, 0, 0, 0, 0);
|
'cpu',
|
||||||
static Cpus get cpus =>
|
0,
|
||||||
Cpus([_initOneTimeCpuStatus], [_initOneTimeCpuStatus]);
|
0,
|
||||||
static NetSpeedPart get _initNetSpeedPart =>
|
0,
|
||||||
NetSpeedPart('', BigInt.zero, BigInt.zero, 0);
|
0,
|
||||||
static NetSpeed get netSpeed =>
|
0,
|
||||||
NetSpeed([_initNetSpeedPart], [_initNetSpeedPart]);
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
static Cpus get cpus => Cpus(
|
||||||
|
[_initOneTimeCpuStatus],
|
||||||
|
[_initOneTimeCpuStatus],
|
||||||
|
);
|
||||||
|
static NetSpeedPart get _initNetSpeedPart => NetSpeedPart(
|
||||||
|
'',
|
||||||
|
BigInt.zero,
|
||||||
|
BigInt.zero,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
static NetSpeed get netSpeed => NetSpeed(
|
||||||
|
[_initNetSpeedPart],
|
||||||
|
[_initNetSpeedPart],
|
||||||
|
);
|
||||||
static ServerStatus get status => ServerStatus(
|
static ServerStatus get status => ServerStatus(
|
||||||
cpu: cpus,
|
cpu: cpus,
|
||||||
mem: const Memory(total: 1, free: 1, avail: 1),
|
mem: const Memory(
|
||||||
disk: [
|
total: 1,
|
||||||
Disk(
|
free: 1,
|
||||||
path: '/',
|
avail: 1,
|
||||||
mount: '/',
|
),
|
||||||
usedPercent: 0,
|
disk: [
|
||||||
used: BigInt.zero,
|
Disk(
|
||||||
size: BigInt.one,
|
fs: '/',
|
||||||
avail: BigInt.zero,
|
mount: '/',
|
||||||
),
|
usedPercent: 0,
|
||||||
],
|
used: BigInt.zero,
|
||||||
tcp: const Conn(maxConn: 0, active: 0, passive: 0, fail: 0),
|
size: BigInt.one,
|
||||||
netSpeed: netSpeed,
|
avail: BigInt.zero,
|
||||||
swap: const Swap(total: 0, free: 0, cached: 0),
|
)
|
||||||
system: SystemType.linux,
|
],
|
||||||
temps: Temperatures(),
|
tcp: const Conn(maxConn: 0, active: 0, passive: 0, fail: 0),
|
||||||
diskIO: DiskIO([], []),
|
netSpeed: netSpeed,
|
||||||
diskSmart: const [],
|
swap: const Swap(
|
||||||
);
|
total: 0,
|
||||||
|
free: 0,
|
||||||
|
cached: 0,
|
||||||
|
),
|
||||||
|
system: SystemType.linux,
|
||||||
|
temps: Temperatures(),
|
||||||
|
diskIO: DiskIO([], []),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:server_box/data/store/container.dart';
|
import 'package:server_box/data/store/container.dart';
|
||||||
import 'package:server_box/data/store/history.dart';
|
import 'package:server_box/data/store/history.dart';
|
||||||
|
import 'package:server_box/data/store/no_backup.dart';
|
||||||
import 'package:server_box/data/store/private_key.dart';
|
import 'package:server_box/data/store/private_key.dart';
|
||||||
import 'package:server_box/data/store/server.dart';
|
import 'package:server_box/data/store/server.dart';
|
||||||
import 'package:server_box/data/store/setting.dart';
|
import 'package:server_box/data/store/setting.dart';
|
||||||
@@ -15,7 +16,7 @@ abstract final class Stores {
|
|||||||
static final history = HistoryStore.instance;
|
static final history = HistoryStore.instance;
|
||||||
|
|
||||||
/// All stores that need backup
|
/// All stores that need backup
|
||||||
static final List<HiveStore> _allBackup = [
|
static final List<PersistentStore> _allBackup = [
|
||||||
SettingStore.instance,
|
SettingStore.instance,
|
||||||
ServerStore.instance,
|
ServerStore.instance,
|
||||||
ContainerStore.instance,
|
ContainerStore.instance,
|
||||||
@@ -26,24 +27,15 @@ abstract final class Stores {
|
|||||||
|
|
||||||
static Future<void> init() async {
|
static Future<void> init() async {
|
||||||
await Future.wait(_allBackup.map((store) => store.init()));
|
await Future.wait(_allBackup.map((store) => store.init()));
|
||||||
|
await NoBackupStore.instance.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get lastModTime {
|
static int? get lastModTime {
|
||||||
var lastModTime = 0;
|
int? lastModTime = 0;
|
||||||
for (final store in _allBackup) {
|
for (final store in _allBackup) {
|
||||||
final last = store.lastUpdateTs;
|
final last = store.box.lastModified ?? 0;
|
||||||
if (last == null) {
|
if (last > (lastModTime ?? 0)) {
|
||||||
continue;
|
lastModTime = last;
|
||||||
}
|
|
||||||
var lastModTimeTs = 0;
|
|
||||||
for (final item in last.entries) {
|
|
||||||
final ts = item.value;
|
|
||||||
if (ts > lastModTimeTs) {
|
|
||||||
lastModTimeTs = ts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lastModTimeTs > lastModTime) {
|
|
||||||
lastModTime = lastModTimeTs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lastModTime;
|
return lastModTime;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:server_box/data/res/store.dart';
|
|||||||
|
|
||||||
const _keyConfig = 'providerConfig';
|
const _keyConfig = 'providerConfig';
|
||||||
|
|
||||||
class ContainerStore extends HiveStore {
|
class ContainerStore extends PersistentStore {
|
||||||
ContainerStore._() : super('docker');
|
ContainerStore._() : super('docker');
|
||||||
|
|
||||||
static final instance = ContainerStore._();
|
static final instance = ContainerStore._();
|
||||||
@@ -14,7 +14,8 @@ class ContainerStore extends HiveStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void put(String id, String host) {
|
void put(String id, String host) {
|
||||||
set(id, host);
|
box.put(id, host);
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
ContainerType getType([String id = '']) {
|
ContainerType getType([String id = '']) {
|
||||||
@@ -29,17 +30,16 @@ class ContainerStore extends HiveStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ContainerType get defaultType {
|
ContainerType get defaultType {
|
||||||
if (Stores.setting.usePodman.get()) return ContainerType.podman;
|
if (Stores.setting.usePodman.fetch()) return ContainerType.podman;
|
||||||
return ContainerType.docker;
|
return ContainerType.docker;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setType(ContainerType type, [String id = '']) {
|
void setType(ContainerType type, [String id = '']) {
|
||||||
if (type == defaultType) {
|
if (type == defaultType) {
|
||||||
// box.delete(_keyConfig + id);
|
box.delete(_keyConfig + id);
|
||||||
remove(_keyConfig + id);
|
|
||||||
} else {
|
} else {
|
||||||
// box.put(_keyConfig + id, type.toString());
|
box.put(_keyConfig + id, type.toString());
|
||||||
set(_keyConfig + id, type.toString());
|
|
||||||
}
|
}
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:hive_ce_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
|
|
||||||
/// index from 0 -> n : latest -> oldest
|
/// index from 0 -> n : latest -> oldest
|
||||||
class _ListHistory {
|
class _ListHistory {
|
||||||
@@ -18,6 +18,7 @@ class _ListHistory {
|
|||||||
_history.remove(path);
|
_history.remove(path);
|
||||||
_history.insert(0, path);
|
_history.insert(0, path);
|
||||||
_box.put(_name, _history);
|
_box.put(_name, _history);
|
||||||
|
_box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
List get all => _history;
|
List get all => _history;
|
||||||
@@ -38,12 +39,13 @@ class _MapHistory {
|
|||||||
void put(String id, String val) {
|
void put(String id, String val) {
|
||||||
_history[id] = val;
|
_history[id] = val;
|
||||||
_box.put(_name, _history);
|
_box.put(_name, _history);
|
||||||
|
_box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
String? fetch(String id) => _history[id];
|
String? fetch(String id) => _history[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
class HistoryStore extends HiveStore {
|
class HistoryStore extends PersistentStore {
|
||||||
HistoryStore._() : super('history');
|
HistoryStore._() : super('history');
|
||||||
|
|
||||||
static final instance = HistoryStore._();
|
static final instance = HistoryStore._();
|
||||||
@@ -56,6 +58,5 @@ class HistoryStore extends HiveStore {
|
|||||||
late final sshCmds = _ListHistory(box: box, name: 'sshCmds');
|
late final sshCmds = _ListHistory(box: box, name: 'sshCmds');
|
||||||
|
|
||||||
/// Notify users that this app will write script to server to works properly
|
/// Notify users that this app will write script to server to works properly
|
||||||
late final writeScriptTipShown =
|
late final writeScriptTipShown = property('writeScriptTipShown', false);
|
||||||
propertyDefault('writeScriptTipShown', false);
|
|
||||||
}
|
}
|
||||||
|
|||||||
49
lib/data/store/no_backup.dart
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
import 'package:server_box/data/res/build_data.dart';
|
||||||
|
import 'package:server_box/data/res/store.dart';
|
||||||
|
|
||||||
|
final class NoBackupStore extends PersistentStore {
|
||||||
|
NoBackupStore._() : super('no_backup');
|
||||||
|
|
||||||
|
static final instance = NoBackupStore._();
|
||||||
|
|
||||||
|
/// Only valid on iOS and macOS
|
||||||
|
late final icloudSync = property('icloudSync', false);
|
||||||
|
|
||||||
|
/// Webdav sync
|
||||||
|
late final webdavSync = property('webdavSync', false);
|
||||||
|
late final webdavUrl = property('webdavUrl', '');
|
||||||
|
late final webdavUser = property('webdavUser', '');
|
||||||
|
late final webdavPwd = property('webdavPwd', '');
|
||||||
|
|
||||||
|
void migrate() {
|
||||||
|
if (BuildData.build > 1076) return;
|
||||||
|
|
||||||
|
final settings = Stores.setting;
|
||||||
|
final icloudSync_ = settings.box.get('icloudSync');
|
||||||
|
if (icloudSync_ is bool) {
|
||||||
|
icloudSync.put(icloudSync_);
|
||||||
|
settings.box.delete('icloudSync');
|
||||||
|
}
|
||||||
|
final webdavSync_ = settings.box.get('webdavSync');
|
||||||
|
if (webdavSync_ is bool) {
|
||||||
|
webdavSync.put(webdavSync_);
|
||||||
|
settings.box.delete('webdavSync');
|
||||||
|
}
|
||||||
|
final webdavUrl_ = settings.box.get('webdavUrl');
|
||||||
|
if (webdavUrl_ is String) {
|
||||||
|
webdavUrl.put(webdavUrl_);
|
||||||
|
settings.box.delete('webdavUrl');
|
||||||
|
}
|
||||||
|
final webdavUser_ = settings.box.get('webdavUser');
|
||||||
|
if (webdavUser_ is String) {
|
||||||
|
webdavUser.put(webdavUser_);
|
||||||
|
settings.box.delete('webdavUser');
|
||||||
|
}
|
||||||
|
final webdavPwd_ = settings.box.get('webdavPwd');
|
||||||
|
if (webdavPwd_ is String) {
|
||||||
|
webdavPwd.put(webdavPwd_);
|
||||||
|
settings.box.delete('webdavPwd');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,49 +2,35 @@ import 'package:fl_lib/fl_lib.dart';
|
|||||||
|
|
||||||
import 'package:server_box/data/model/server/private_key_info.dart';
|
import 'package:server_box/data/model/server/private_key_info.dart';
|
||||||
|
|
||||||
class PrivateKeyStore extends HiveStore {
|
class PrivateKeyStore extends PersistentStore {
|
||||||
PrivateKeyStore._() : super('key');
|
PrivateKeyStore._() : super('key');
|
||||||
|
|
||||||
static final instance = PrivateKeyStore._();
|
static final instance = PrivateKeyStore._();
|
||||||
|
|
||||||
void put(PrivateKeyInfo info) {
|
void put(PrivateKeyInfo info) {
|
||||||
set(info.id, info);
|
box.put(info.id, info);
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PrivateKeyInfo> fetch() {
|
List<PrivateKeyInfo> fetch() {
|
||||||
|
final keys = box.keys;
|
||||||
final ps = <PrivateKeyInfo>[];
|
final ps = <PrivateKeyInfo>[];
|
||||||
for (final key in keys()) {
|
for (final key in keys) {
|
||||||
final s = get<PrivateKeyInfo>(
|
final s = box.get(key);
|
||||||
key,
|
if (s != null && s is PrivateKeyInfo) {
|
||||||
fromObj: (val) {
|
|
||||||
if (val is PrivateKeyInfo) return val;
|
|
||||||
if (val is Map<dynamic, dynamic>) {
|
|
||||||
final map = val.toStrDynMap;
|
|
||||||
if (map == null) return null;
|
|
||||||
try {
|
|
||||||
final pki = PrivateKeyInfo.fromJson(map as Map<String, dynamic>);
|
|
||||||
put(pki);
|
|
||||||
return pki;
|
|
||||||
} catch (e) {
|
|
||||||
dprint('Parsing PrivateKeyInfo from JSON', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (s != null) {
|
|
||||||
ps.add(s);
|
ps.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrivateKeyInfo? fetchOne(String? id) {
|
PrivateKeyInfo? get(String? id) {
|
||||||
if (id == null) return null;
|
if (id == null) return null;
|
||||||
return box.get(id);
|
return box.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete(PrivateKeyInfo s) {
|
void delete(PrivateKeyInfo s) {
|
||||||
remove(s.id);
|
box.delete(s.id);
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,23 @@
|
|||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
|
|
||||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||||
import 'package:server_box/data/store/container.dart';
|
|
||||||
import 'package:server_box/data/store/setting.dart';
|
|
||||||
import 'package:server_box/data/store/snippet.dart';
|
|
||||||
|
|
||||||
class ServerStore extends HiveStore {
|
class ServerStore extends PersistentStore {
|
||||||
ServerStore._() : super('server');
|
ServerStore._() : super('server');
|
||||||
|
|
||||||
static final instance = ServerStore._();
|
static final instance = ServerStore._();
|
||||||
|
|
||||||
void put(Spi info) {
|
void put(Spi info) {
|
||||||
set(info.id, info);
|
box.put(info.id, info);
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Spi> fetch() {
|
List<Spi> fetch() {
|
||||||
|
final ids = box.keys;
|
||||||
final List<Spi> ss = [];
|
final List<Spi> ss = [];
|
||||||
for (final id in keys()) {
|
for (final id in ids) {
|
||||||
final s = get<Spi>(
|
final s = box.get(id);
|
||||||
id,
|
if (s != null && s is Spi) {
|
||||||
fromObj: (val) {
|
|
||||||
if (val is Spi) return val;
|
|
||||||
if (val is Map<dynamic, dynamic>) {
|
|
||||||
final map = val.toStrDynMap;
|
|
||||||
if (map == null) return null;
|
|
||||||
try {
|
|
||||||
final spi = Spi.fromJson(map as Map<String, dynamic>);
|
|
||||||
put(spi);
|
|
||||||
return spi;
|
|
||||||
} catch (e) {
|
|
||||||
dprint('Parsing Spi from JSON', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (s != null) {
|
|
||||||
ss.add(s);
|
ss.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +25,13 @@ class ServerStore extends HiveStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void delete(String id) {
|
void delete(String id) {
|
||||||
remove(id);
|
box.delete(id);
|
||||||
|
box.updateLastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteAll() {
|
||||||
|
box.clear();
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(Spi old, Spi newInfo) {
|
void update(Spi old, Spi newInfo) {
|
||||||
@@ -54,74 +42,5 @@ class ServerStore extends HiveStore {
|
|||||||
put(newInfo);
|
put(newInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool have(Spi s) => get(s.id) != null;
|
bool have(Spi s) => box.get(s.id) != null;
|
||||||
|
|
||||||
void migrateIds() {
|
|
||||||
final ss = fetch();
|
|
||||||
final idMap = <String, String>{};
|
|
||||||
|
|
||||||
// Collect all old to new ID mappings
|
|
||||||
for (final s in ss) {
|
|
||||||
final newId = s.migrateId();
|
|
||||||
if (newId == null) continue;
|
|
||||||
// Use s.oldId as the key, because s.id would be empty for a server being migrated.
|
|
||||||
// s.oldId represents the identifier used before migration.
|
|
||||||
idMap[s.oldId] = newId;
|
|
||||||
}
|
|
||||||
|
|
||||||
final srvOrder = SettingStore.instance.serverOrder.fetch();
|
|
||||||
final snippets = SnippetStore.instance.fetch();
|
|
||||||
final container = ContainerStore.instance;
|
|
||||||
|
|
||||||
bool srvOrderChanged = false;
|
|
||||||
// Update all references to the servers
|
|
||||||
for (final e in idMap.entries) {
|
|
||||||
final oldId = e.key;
|
|
||||||
final newId = e.value;
|
|
||||||
|
|
||||||
// Replace ids in ordering settings.
|
|
||||||
final srvIdx = srvOrder.indexOf(oldId);
|
|
||||||
if (srvIdx != -1) {
|
|
||||||
srvOrder[srvIdx] = newId;
|
|
||||||
srvOrderChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace ids in jump server settings.
|
|
||||||
final spi = get<Spi>(newId);
|
|
||||||
if (spi != null) {
|
|
||||||
final jumpId = spi.jumpId; // This could be an oldId.
|
|
||||||
// Check if this jumpId corresponds to a server that was also migrated.
|
|
||||||
if (jumpId != null && idMap.containsKey(jumpId)) {
|
|
||||||
final newJumpId = idMap[jumpId];
|
|
||||||
if (spi.jumpId != newJumpId) {
|
|
||||||
final newSpi = spi.copyWith(jumpId: newJumpId);
|
|
||||||
update(spi, newSpi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace ids in [Snippet]
|
|
||||||
for (final snippet in snippets) {
|
|
||||||
final autoRunsOn = snippet.autoRunOn;
|
|
||||||
final idx = autoRunsOn?.indexOf(oldId);
|
|
||||||
if (idx != null && idx != -1) {
|
|
||||||
final newAutoRunsOn = List<String>.from(autoRunsOn ?? []);
|
|
||||||
newAutoRunsOn[idx] = newId;
|
|
||||||
final newSnippet = snippet.copyWith(autoRunOn: newAutoRunsOn);
|
|
||||||
SnippetStore.instance.update(snippet, newSnippet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace ids in [Container]
|
|
||||||
final dockerHost = container.fetch(oldId);
|
|
||||||
if (dockerHost != null) {
|
|
||||||
container.remove(oldId);
|
|
||||||
container.set(newId, dockerHost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (srvOrderChanged) {
|
|
||||||
SettingStore.instance.serverOrder.put(srvOrder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +1,98 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:fl_lib/fl_lib.dart';
|
import 'package:fl_lib/fl_lib.dart';
|
||||||
import 'package:server_box/data/model/app/menu/server_func.dart';
|
import 'package:server_box/data/model/app/menu/server_func.dart';
|
||||||
import 'package:server_box/data/model/app/net_view.dart';
|
|
||||||
import 'package:server_box/data/model/app/server_detail_card.dart';
|
import 'package:server_box/data/model/app/server_detail_card.dart';
|
||||||
import 'package:server_box/data/model/ssh/virtual_key.dart';
|
import 'package:server_box/data/model/ssh/virtual_key.dart';
|
||||||
|
|
||||||
|
import 'package:server_box/data/model/app/net_view.dart';
|
||||||
import 'package:server_box/data/res/default.dart';
|
import 'package:server_box/data/res/default.dart';
|
||||||
|
|
||||||
class SettingStore extends HiveStore {
|
class SettingStore extends PersistentStore {
|
||||||
SettingStore._() : super('setting');
|
SettingStore._() : super('setting');
|
||||||
|
|
||||||
static final instance = SettingStore._();
|
static final instance = SettingStore._();
|
||||||
|
|
||||||
|
// ------BEGIN------
|
||||||
|
//
|
||||||
|
// These settings are not displayed in the settings page
|
||||||
|
// You can edit them in the settings json editor (by long press the settings
|
||||||
|
// item in the drawer of the home page)
|
||||||
|
|
||||||
|
/// Discussion #146
|
||||||
|
late final serverTabUseOldUI = property('serverTabUseOldUI', false);
|
||||||
|
|
||||||
/// Time out for server connect and more...
|
/// Time out for server connect and more...
|
||||||
late final timeout = propertyDefault('timeOut', 5);
|
late final timeout = property('timeOut', 5);
|
||||||
|
|
||||||
/// Record history of SFTP path and etc.
|
/// Record history of SFTP path and etc.
|
||||||
late final recordHistory = propertyDefault('recordHistory', true);
|
late final recordHistory = property('recordHistory', true);
|
||||||
|
|
||||||
/// Lanch page idx
|
/// Lanch page idx
|
||||||
// late final launchPage = property('launchPage', Defaults.launchPageIdx);
|
// late final launchPage = property('launchPage', Defaults.launchPageIdx);
|
||||||
|
|
||||||
/// Disk view: amount / IO
|
/// Disk view: amount / IO
|
||||||
late final serverTabPreferDiskAmount = propertyDefault(
|
late final serverTabPreferDiskAmount = property(
|
||||||
'serverTabPreferDiskAmount',
|
'serverTabPreferDiskAmount',
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ------END------
|
||||||
|
|
||||||
/// Bigger for bigger font size
|
/// Bigger for bigger font size
|
||||||
/// 1.0 means 100%
|
/// 1.0 means 100%
|
||||||
/// Warning: This may cause some UI issues
|
/// Warning: This may cause some UI issues
|
||||||
late final textFactor = propertyDefault('textFactor', 1.0);
|
late final textFactor = property('textFactor', 1.0);
|
||||||
|
|
||||||
/// The seed of color scheme
|
/// The seed of color scheme
|
||||||
late final colorSeed = propertyDefault('primaryColor', 4287106639);
|
late final colorSeed = property('primaryColor', 4287106639);
|
||||||
|
|
||||||
late final serverStatusUpdateInterval = propertyDefault(
|
late final serverStatusUpdateInterval = property(
|
||||||
'serverStatusUpdateInterval',
|
'serverStatusUpdateInterval',
|
||||||
Defaults.updateInterval,
|
Defaults.updateInterval,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Max retry count when connect to server
|
// Max retry count when connect to server
|
||||||
late final maxRetryCount = propertyDefault('maxRetryCount', 2);
|
late final maxRetryCount = property('maxRetryCount', 2);
|
||||||
|
|
||||||
// Night mode: 0 -> auto, 1 -> light, 2 -> dark, 3 -> AMOLED, 4 -> AUTO-AMOLED
|
// Night mode: 0 -> auto, 1 -> light, 2 -> dark, 3 -> AMOLED, 4 -> AUTO-AMOLED
|
||||||
late final themeMode = propertyDefault('themeMode', 0);
|
late final themeMode = property('themeMode', 0);
|
||||||
|
|
||||||
// Font file path
|
// Font file path
|
||||||
late final fontPath = propertyDefault('fontPath', '');
|
late final fontPath = property('fontPath', '');
|
||||||
|
|
||||||
// Backgroud running (Android)
|
// Backgroud running (Android)
|
||||||
late final bgRun = propertyDefault('bgRun', isAndroid);
|
late final bgRun = property('bgRun', isAndroid);
|
||||||
|
|
||||||
// Server order
|
// Server order
|
||||||
late final serverOrder = listProperty<String>('serverOrder');
|
late final serverOrder = listProperty<String>('serverOrder', []);
|
||||||
|
|
||||||
late final snippetOrder = listProperty<String>('snippetOrder');
|
late final snippetOrder = listProperty<String>('snippetOrder', []);
|
||||||
|
|
||||||
// Server details page cards order
|
// Server details page cards order
|
||||||
late final detailCardOrder = listProperty(
|
late final detailCardOrder = listProperty(
|
||||||
'detailCardOrder',
|
'detailCardOrder',
|
||||||
defaultValue: ServerDetailCards.values.map((e) => e.name).toList(),
|
ServerDetailCards.values.map((e) => e.name).toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// SSH term font size
|
// SSH term font size
|
||||||
late final termFontSize = propertyDefault('termFontSize', 13.0);
|
late final termFontSize = property('termFontSize', 13.0);
|
||||||
|
|
||||||
// Locale
|
// Locale
|
||||||
late final locale = propertyDefault('locale', '');
|
late final locale = property('locale', '');
|
||||||
|
|
||||||
// SSH virtual key (ctrl | alt) auto turn off
|
// SSH virtual key (ctrl | alt) auto turn off
|
||||||
late final sshVirtualKeyAutoOff = propertyDefault(
|
late final sshVirtualKeyAutoOff = property('sshVirtualKeyAutoOff', true);
|
||||||
'sshVirtualKeyAutoOff',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
late final editorFontSize = propertyDefault('editorFontSize', 12.5);
|
late final editorFontSize = property('editorFontSize', 12.5);
|
||||||
|
|
||||||
// Editor theme
|
// Editor theme
|
||||||
late final editorTheme = propertyDefault('editorTheme', Defaults.editorTheme);
|
late final editorTheme = property('editorTheme', Defaults.editorTheme);
|
||||||
|
|
||||||
late final editorDarkTheme = propertyDefault(
|
late final editorDarkTheme =
|
||||||
'editorDarkTheme',
|
property('editorDarkTheme', Defaults.editorDarkTheme);
|
||||||
Defaults.editorDarkTheme,
|
|
||||||
);
|
|
||||||
|
|
||||||
late final fullScreen = propertyDefault('fullScreen', false);
|
late final fullScreen = property('fullScreen', false);
|
||||||
|
|
||||||
late final fullScreenJitter = propertyDefault('fullScreenJitter', true);
|
late final fullScreenJitter = property('fullScreenJitter', true);
|
||||||
|
|
||||||
// late final fullScreenRotateQuarter = property(
|
// late final fullScreenRotateQuarter = property(
|
||||||
// 'fullScreenRotateQuarter',
|
// 'fullScreenRotateQuarter',
|
||||||
@@ -99,175 +104,140 @@ class SettingStore extends HiveStore {
|
|||||||
// TextInputType.text.index,
|
// TextInputType.text.index,
|
||||||
// );
|
// );
|
||||||
|
|
||||||
late final sshVirtKeys = listProperty<int>(
|
late final sshVirtKeys = listProperty(
|
||||||
'sshVirtKeys',
|
'sshVirtKeys',
|
||||||
defaultValue: VirtKeyX.defaultOrder.map((e) => e.index).toList(),
|
VirtKeyX.defaultOrder.map((e) => e.index).toList(),
|
||||||
fromObj: (val) => List<int>.from(val as List),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
late final netViewType = propertyDefault(
|
late final netViewType = property('netViewType', NetViewType.speed);
|
||||||
'netViewType',
|
|
||||||
NetViewType.speed,
|
|
||||||
fromObj: (val) => NetViewType.values.firstWhereOrNull((e) => e.name == val),
|
|
||||||
toObj: (type) => type?.name,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Only valid on iOS
|
// Only valid on iOS
|
||||||
late final autoUpdateHomeWidget = propertyDefault(
|
late final autoUpdateHomeWidget = property('autoUpdateHomeWidget', isIOS);
|
||||||
'autoUpdateHomeWidget',
|
|
||||||
isIOS,
|
|
||||||
);
|
|
||||||
|
|
||||||
late final autoCheckAppUpdate = propertyDefault('autoCheckAppUpdate', true);
|
late final autoCheckAppUpdate = property('autoCheckAppUpdate', true);
|
||||||
|
|
||||||
/// Display server tab function buttons on the bottom of each server card if [true]
|
/// Display server tab function buttons on the bottom of each server card if [true]
|
||||||
///
|
///
|
||||||
/// Otherwise, display them on the top of server detail page
|
/// Otherwise, display them on the top of server detail page
|
||||||
late final moveServerFuncs = propertyDefault(
|
late final moveServerFuncs = property('moveOutServerTabFuncBtns', false);
|
||||||
'moveOutServerTabFuncBtns',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Whether use `rm -r` to delete directory on SFTP
|
/// Whether use `rm -r` to delete directory on SFTP
|
||||||
late final sftpRmrDir = propertyDefault('sftpRmrDir', false);
|
late final sftpRmrDir = property('sftpRmrDir', false);
|
||||||
|
|
||||||
/// Whether use system's primary color as the app's primary color
|
/// Whether use system's primary color as the app's primary color
|
||||||
late final useSystemPrimaryColor = propertyDefault(
|
late final useSystemPrimaryColor = property('useSystemPrimaryColor', false);
|
||||||
'useSystemPrimaryColor',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Only valid on iOS / Android / Windows
|
/// Only valid on iOS / Android / Windows
|
||||||
late final useBioAuth = propertyDefault('useBioAuth', false);
|
late final useBioAuth = property('useBioAuth', false);
|
||||||
|
|
||||||
/// The performance of highlight is bad
|
/// The performance of highlight is bad
|
||||||
late final editorHighlight = propertyDefault('editorHighlight', true);
|
late final editorHighlight = property('editorHighlight', true);
|
||||||
|
|
||||||
/// Open SFTP with last viewed path
|
/// Open SFTP with last viewed path
|
||||||
late final sftpOpenLastPath = propertyDefault('sftpOpenLastPath', true);
|
late final sftpOpenLastPath = property('sftpOpenLastPath', true);
|
||||||
|
|
||||||
/// Show folders first in SFTP file browser
|
/// Show folders first in SFTP file browser
|
||||||
late final sftpShowFoldersFirst = propertyDefault(
|
late final sftpShowFoldersFirst = property('sftpShowFoldersFirst', true);
|
||||||
'sftpShowFoldersFirst',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Show tip of suspend
|
/// Show tip of suspend
|
||||||
late final showSuspendTip = propertyDefault('showSuspendTip', true);
|
late final showSuspendTip = property('showSuspendTip', true);
|
||||||
|
|
||||||
/// Whether collapse UI items by default
|
/// Whether collapse UI items by default
|
||||||
late final collapseUIDefault = propertyDefault('collapseUIDefault', true);
|
late final collapseUIDefault = property('collapseUIDefault', true);
|
||||||
|
|
||||||
late final serverFuncBtns = listProperty(
|
late final serverFuncBtns = listProperty(
|
||||||
'serverBtns',
|
'serverBtns',
|
||||||
defaultValue: ServerFuncBtn.defaultIdxs,
|
ServerFuncBtn.defaultIdxs,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Docker is more popular than podman, set to `false` to use docker
|
/// Docker is more popular than podman, set to `false` to use docker
|
||||||
late final usePodman = propertyDefault('usePodman', false);
|
late final usePodman = property('usePodman', false);
|
||||||
|
|
||||||
/// Try to use `sudo` to run docker command
|
/// Try to use `sudo` to run docker command
|
||||||
late final containerTrySudo = propertyDefault('containerTrySudo', true);
|
late final containerTrySudo = property('containerTrySudo', true);
|
||||||
|
|
||||||
/// Keep previous server status when err occurs
|
/// Keep previous server status when err occurs
|
||||||
late final keepStatusWhenErr = propertyDefault('keepStatusWhenErr', false);
|
late final keepStatusWhenErr = property('keepStatusWhenErr', false);
|
||||||
|
|
||||||
/// Parse container stat
|
/// Parse container stat
|
||||||
late final containerParseStat = propertyDefault('containerParseStat', true);
|
late final containerParseStat = property('containerParseStat', true);
|
||||||
|
|
||||||
/// Auto refresh container status
|
/// Auto refresh container status
|
||||||
late final containerAutoRefresh = propertyDefault(
|
late final contaienrAutoRefresh = property('contaienrAutoRefresh', true);
|
||||||
'containerAutoRefresh',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Use double column servers page on Desktop
|
/// Use double column servers page on Desktop
|
||||||
late final doubleColumnServersPage = propertyDefault(
|
late final doubleColumnServersPage = property(
|
||||||
'doubleColumnServersPage',
|
'doubleColumnServersPage',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Ignore local network device (eg: br-xxx, ovs-system...)
|
/// Ignore local network device (eg: br-xxx, ovs-system...)
|
||||||
/// when building traffic view on server tab
|
/// when building traffic view on server tab
|
||||||
//late final ignoreLocalNet = propertyDefault('ignoreLocalNet', true);
|
//late final ignoreLocalNet = property('ignoreLocalNet', true);
|
||||||
|
|
||||||
/// Remerber pwd in memory
|
/// Remerber pwd in memory
|
||||||
/// Used for [DialogX.showPwdDialog]
|
/// Used for [DialogX.showPwdDialog]
|
||||||
late final rememberPwdInMem = propertyDefault('rememberPwdInMem', true);
|
late final rememberPwdInMem = property('rememberPwdInMem', true);
|
||||||
|
|
||||||
/// SSH Term Theme
|
/// SSH Term Theme
|
||||||
/// 0: follow app theme, 1: light, 2: dark
|
/// 0: follow app theme, 1: light, 2: dark
|
||||||
late final termTheme = propertyDefault('termTheme', 0);
|
late final termTheme = property('termTheme', 0);
|
||||||
|
|
||||||
/// Compatiablity for Chinese Android.
|
/// Compatiablity for Chinese Android.
|
||||||
/// Set it to true, if you use Safe Keyboard on Chinese Android
|
/// Set it to true, if you use Safe Keyboard on Chinese Android
|
||||||
// late final cnKeyboardComp = propertyDefault('cnKeyboardComp', false);
|
// late final cnKeyboardComp = property('cnKeyboardComp', false);
|
||||||
|
|
||||||
late final lastVer = propertyDefault('lastVer', 0);
|
late final lastVer = property('lastVer', 0);
|
||||||
|
|
||||||
/// Use CupertinoPageRoute for all routes
|
/// Use CupertinoPageRoute for all routes
|
||||||
late final cupertinoRoute = propertyDefault('cupertinoRoute', isIOS);
|
late final cupertinoRoute = property('cupertinoRoute', isIOS);
|
||||||
|
|
||||||
/// Hide title bar on desktop
|
/// Hide title bar on desktop
|
||||||
late final hideTitleBar = propertyDefault('hideTitleBar', isDesktop);
|
late final hideTitleBar = property('hideTitleBar', isDesktop);
|
||||||
|
|
||||||
/// Display CPU view as progress, also called as old CPU view
|
/// Display CPU view as progress, also called as old CPU view
|
||||||
late final cpuViewAsProgress = propertyDefault('cpuViewAsProgress', false);
|
late final cpuViewAsProgress = property('cpuViewAsProgress', false);
|
||||||
|
|
||||||
late final displayCpuIndex = propertyDefault('displayCpuIndex', true);
|
late final displayCpuIndex = property('displayCpuIndex', true);
|
||||||
|
|
||||||
late final editorSoftWrap = propertyDefault('editorSoftWrap', isIOS);
|
late final editorSoftWrap = property('editorSoftWrap', isIOS);
|
||||||
|
|
||||||
late final sshTermHelpShown = propertyDefault('sshTermHelpShown', false);
|
late final sshTermHelpShown = property('sshTermHelpShown', false);
|
||||||
|
|
||||||
late final horizonVirtKey = propertyDefault('horizonVirtKey', false);
|
late final horizonVirtKey = property('horizonVirtKey', false);
|
||||||
|
|
||||||
/// general wake lock
|
/// general wake lock
|
||||||
late final generalWakeLock = propertyDefault('generalWakeLock', false);
|
late final generalWakeLock = property('generalWakeLock', false);
|
||||||
|
|
||||||
/// ssh page
|
/// ssh page
|
||||||
late final sshWakeLock = propertyDefault('sshWakeLock', true);
|
late final sshWakeLock = property('sshWakeLock', true);
|
||||||
late final sshBgImage = propertyDefault('sshBgImage', '');
|
|
||||||
late final sshBgOpacity = propertyDefault('sshBgOpacity', 0.3);
|
|
||||||
late final sshBlurRadius = propertyDefault('sshBlurRadius', 0.0);
|
|
||||||
|
|
||||||
/// fmt: https://example.com/{DIST}-{BRIGHT}.png
|
/// fmt: https://example.com/{DIST}-{BRIGHT}.png
|
||||||
late final serverLogoUrl = propertyDefault('serverLogoUrl', '');
|
late final serverLogoUrl = property('serverLogoUrl', '');
|
||||||
|
|
||||||
late final betaTest = propertyDefault('betaTest', false);
|
late final betaTest = property('betaTest', false);
|
||||||
|
|
||||||
/// For desktop only.
|
/// If it's empty, skip change window size.
|
||||||
/// Record the position and size of the window.
|
/// Format: {width}x{height}
|
||||||
late final windowState = property<WindowState>(
|
late final windowSize = property('windowSize', '');
|
||||||
'windowState',
|
|
||||||
fromObj: (raw) =>
|
|
||||||
WindowState.fromJson(jsonDecode(raw as String) as Map<String, dynamic>),
|
|
||||||
toObj: (state) => state == null ? null : jsonEncode(state.toJson()),
|
|
||||||
);
|
|
||||||
|
|
||||||
late final introVer = propertyDefault('introVer', 0);
|
late final introVer = property('introVer', 0);
|
||||||
|
|
||||||
late final letterCache = propertyDefault('letterCache', false);
|
late final letterCache = property('letterCache', false);
|
||||||
|
|
||||||
/// Set it to `$EDITOR`, `vim` and etc. to use remote system editor in SSH terminal.
|
/// Set it to `$EDITOR`, `vim` and etc. to use remote system editor in SSH terminal.
|
||||||
/// Set it empty to use local editor GUI.
|
/// Set it empty to use local editor GUI.
|
||||||
late final sftpEditor = propertyDefault('sftpEditor', '');
|
late final sftpEditor = property('sftpEditor', '');
|
||||||
|
|
||||||
/// Preferred terminal emulator command on desktop
|
// Never show these settings for users
|
||||||
late final desktopTerminal = propertyDefault(
|
//
|
||||||
'desktopTerminal',
|
// ------BEGIN------
|
||||||
'x-terminal-emulator',
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Run foreground service on Android, if the SSH terminal is running
|
|
||||||
late final fgService = propertyDefault('fgService', false);
|
|
||||||
|
|
||||||
/// Close the editor after saving
|
|
||||||
late final closeAfterSave = propertyDefault('closeAfterSave', false);
|
|
||||||
|
|
||||||
/// Version of store db
|
/// Version of store db
|
||||||
late final storeVersion = propertyDefault('storeVersion', 0);
|
late final storeVersion = property('storeVersion', 0);
|
||||||
|
|
||||||
/// Have notified user for notificaiton permission or not
|
/// Have notified user for notificaiton permission or not
|
||||||
late final noNotiPerm = propertyDefault('noNotiPerm', false);
|
late final noNotiPerm = property('noNotiPerm', false);
|
||||||
|
|
||||||
|
// ------END------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,54 +2,30 @@ import 'package:fl_lib/fl_lib.dart';
|
|||||||
|
|
||||||
import 'package:server_box/data/model/server/snippet.dart';
|
import 'package:server_box/data/model/server/snippet.dart';
|
||||||
|
|
||||||
class SnippetStore extends HiveStore {
|
class SnippetStore extends PersistentStore {
|
||||||
SnippetStore._() : super('snippet');
|
SnippetStore._() : super('snippet');
|
||||||
|
|
||||||
static final instance = SnippetStore._();
|
static final instance = SnippetStore._();
|
||||||
|
|
||||||
void put(Snippet snippet) {
|
void put(Snippet snippet) {
|
||||||
set(snippet.name, snippet);
|
box.put(snippet.name, snippet);
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Snippet> fetch() {
|
List<Snippet> fetch() {
|
||||||
final ss = <Snippet>{};
|
final keys = box.keys;
|
||||||
for (final key in keys()) {
|
final ss = <Snippet>[];
|
||||||
final s = get<Snippet>(
|
for (final key in keys) {
|
||||||
key,
|
final s = box.get(key);
|
||||||
fromObj: (val) {
|
if (s != null && s is Snippet) {
|
||||||
if (val is Snippet) return val;
|
|
||||||
if (val is Map<dynamic, dynamic>) {
|
|
||||||
final map = val.toStrDynMap;
|
|
||||||
if (map == null) return null;
|
|
||||||
try {
|
|
||||||
final snippet = Snippet.fromJson(map as Map<String, dynamic>);
|
|
||||||
put(snippet);
|
|
||||||
return snippet;
|
|
||||||
} catch (e) {
|
|
||||||
dprint('Parsing Snippet from JSON', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (s != null) {
|
|
||||||
ss.add(s);
|
ss.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ss.toList();
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete(Snippet s) {
|
void delete(Snippet s) {
|
||||||
remove(s.name);
|
box.delete(s.name);
|
||||||
|
box.updateLastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(Snippet old, Snippet newInfo) {
|
|
||||||
if (!have(old)) {
|
|
||||||
throw Exception('Old snippet: $old not found');
|
|
||||||
}
|
|
||||||
delete(old);
|
|
||||||
put(newInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool have(Snippet s) => get(s.name) != null;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,779 +0,0 @@
|
|||||||
// ignore: unused_import
|
|
||||||
import 'package:intl/intl.dart' as intl;
|
|
||||||
import 'l10n.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
|
|
||||||
/// The translations for German (`de`).
|
|
||||||
class AppLocalizationsDe extends AppLocalizations {
|
|
||||||
AppLocalizationsDe([String locale = 'de']) : super(locale);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get aboutThanks =>
|
|
||||||
'Vielen Dank an die folgenden Personen, die daran teilgenommen haben.\n';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get acceptBeta => 'Akzeptieren Sie Testversion-Updates';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get addSystemPrivateKeyTip =>
|
|
||||||
'Derzeit haben Sie keinen privaten Schlüssel, fügen Sie den Schlüssel hinzu, der mit dem System geliefert wird (~/.ssh/id_rsa)?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get added2List => 'Zur Aufgabenliste hinzugefügt';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get addr => 'Adresse';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get alreadyLastDir => 'Bereits im letzten Verzeichnis.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get authFailTip =>
|
|
||||||
'Authentifizierung fehlgeschlagen, bitte überprüfen Sie, ob das Passwort/Schlüssel/Host/Benutzer usw. falsch sind.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoBackupConflict =>
|
|
||||||
'Es kann nur eine automatische Sicherung gleichzeitig aktiviert werden.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoConnect => 'Automatisch verbinden';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoRun => 'Automatischer Start';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoUpdateHomeWidget => 'Home-Widget automatisch aktualisieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupTip =>
|
|
||||||
'Das Backup wird nur einfach verschlüsselt.\nBitte bewahre die Datei sicher auf.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupVersionNotMatch =>
|
|
||||||
'Die Backup-Version stimmt nicht überein.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get battery => 'Batterie';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get bgRun => 'Hintergrundaktualisierung';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get bgRunTip =>
|
|
||||||
'Dieser Schalter bedeutet nur, dass die App versuchen wird, im Hintergrund zu laufen. Ob sie im Hintergrund laufen kann, hängt davon ab, ob die Berechtigungen aktiviert sind oder nicht. Bei nativem Android deaktivieren Sie bitte \"Batterieoptimierung\" in dieser App, und bei miui ändern Sie bitte die Energiesparrichtlinie auf \"Unbegrenzt\".';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get closeAfterSave => 'Speichern und schließen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cmd => 'Command';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get collapseUITip =>
|
|
||||||
'Ob lange Listen in der Benutzeroberfläche standardmäßig eingeklappt werden sollen oder nicht';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get conn => 'Verbindung';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get container => 'Container';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get containerTrySudoTip =>
|
|
||||||
'Zum Beispiel: In der App ist der Benutzer auf aaa eingestellt, aber Docker ist unter dem Root-Benutzer installiert. In diesem Fall müssen Sie diese Option aktivieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get convert => 'Konvertieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get copyPath => 'Pfad kopieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cpuViewAsProgressTip =>
|
|
||||||
'Zeigen Sie die Auslastung jedes CPUs in einem Fortschrittsbalken-Stil an (alter Stil)';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cursorType => 'Cursor-Typ';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmd => 'Benutzerdefinierte Befehle';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmdDocUrl =>
|
|
||||||
'https://github.com/lollipopkit/flutter_server_box/wiki#custom-commands';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmdHint => '\"Befehlsname\": \"Befehl\"';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get decode => 'Decode';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get decompress => 'Dekomprimieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get deleteServers => 'Batch-Löschung von Servern';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get desktopTerminalTip =>
|
|
||||||
'Befehl zum Öffnen des Terminal-Emulators beim Starten von SSH-Sitzungen.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dirEmpty => 'Stelle sicher, dass der Ordner leer ist.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get disconnected => 'Disconnected';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get disk => 'Festplatte';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get diskHealth => 'Festplattengesundheit';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get diskIgnorePath => 'Pfad für Datenträger ignorieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get displayCpuIndex => 'Zeigen Sie den CPU-Index an';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dl2Local(Object fileName) {
|
|
||||||
return 'Datei \"$fileName\" herunterladen?';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dockerEmptyRunningItems =>
|
|
||||||
'Es gibt keine laufenden Container.\nDas könnte daran liegen:\n- Der Docker-Installationsbenutzer ist nicht mit dem in der App konfigurierten Benutzernamen identisch.\n- Die Umgebungsvariable DOCKER_HOST wurde nicht korrekt gelesen. Sie können sie ermitteln, indem Sie `echo \$DOCKER_HOST` im Terminal ausführen.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerImagesFmt(Object count) {
|
|
||||||
return '$count Image(s)';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dockerNotInstalled => 'Docker ist nicht installiert';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerStatusRunningAndStoppedFmt(
|
|
||||||
Object runningCount,
|
|
||||||
Object stoppedCount,
|
|
||||||
) {
|
|
||||||
return '$runningCount aktiv, $stoppedCount container gestoppt.';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerStatusRunningFmt(Object count) {
|
|
||||||
return '$count Container aktiv';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get doubleColumnMode => 'Doppelspaltiger Modus';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get doubleColumnTip =>
|
|
||||||
'Diese Option aktiviert nur die Funktion, ob sie tatsächlich aktiviert werden kann, hängt auch von der Breite des Geräts ab';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editVirtKeys => 'Virtuelle Tasten bearbeiten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editor => 'Editor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editorHighlightTip =>
|
|
||||||
'Die Leistung der aktuellen Codehervorhebung ist schlechter und kann zur Verbesserung optional ausgeschaltet werden.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get emulator => 'Emulator';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get encode => 'Encode';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get envVars => 'Umgebungsvariable';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get experimentalFeature => 'Experimentelles Feature';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get extraArgs => 'Extra args';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fallbackSshDest => 'SSH-Fallback-Ziel';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fdroidReleaseTip =>
|
|
||||||
'Wenn Sie diese App von F-Droid heruntergeladen haben, wird empfohlen, diese Option zu deaktivieren.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fgService => 'Vordergrund-Dienst';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fgServiceTip =>
|
|
||||||
'Nach dem Einschalten kann es bei einigen Gerätemodellen zu Abstürzen kommen. Das Ausschalten kann bei einigen Modellen dazu führen, dass SSH-Verbindungen im Hintergrund nicht aufrechterhalten werden können. Bitte erlauben Sie ServerBox in den Systemeinstellungen Benachrichtigungsrechte, Hintergrundausführung und Selbstaktivierung.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
|
||||||
return 'Datei \'$file\' ist zu groß $size, max $sizeMax';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get followSystem => 'System verfolgen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get font => 'Schriftarten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fontSize => 'Schriftgröße';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get force => 'freiwillig';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreen => 'Vollbildmodus';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenJitter => 'Jitter im Vollbildmodus';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenJitterHelp => 'Einbrennen des Bildschirms verhindern';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenTip =>
|
|
||||||
'Soll der Vollbildmodus aktiviert werden, wenn das Gerät in den Quermodus gedreht wird? Diese Option gilt nur für die Server-Registerkarte.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get goBackQ => 'Zurückkommen?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get goto => 'Pfad öffnen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get hideTitleBar => 'Titelleiste ausblenden';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get highlight => 'Code highlight';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get homeWidgetUrlConfig => 'Home-Widget-Link konfigurieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get host => 'Host';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String httpFailedWithCode(Object code) {
|
|
||||||
return 'Anfrage fehlgeschlagen, Statuscode: $code';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ignoreCert => 'Zertifikat ignorieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get image => 'Image';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get imagesList => 'Images';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get init => 'Initialisieren';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get inner => 'Eingebaut';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get install => 'install';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get installDockerWithUrl =>
|
|
||||||
'Bitte installiere docker zuerst. https://docs.docker.com/engine/install';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get invalid => 'Ungültig';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get jumpServer => 'Server springen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepForeground => 'Stelle sicher, dass die App geöffnet bleibt.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepStatusWhenErr => 'Den letzten Serverstatus beibehalten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepStatusWhenErrTip =>
|
|
||||||
'Nur im Fehlerfall während der Ausführung des Skripts';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keyAuth => 'Schlüsselauthentifzierung';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get letterCache => 'Buchstaben-Caching';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get letterCacheTip =>
|
|
||||||
'Empfohlen, zu deaktivieren, aber nach dem Deaktivieren können keine CJK-Zeichen eingegeben werden.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get license => 'Lizenzen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get location => 'Standort';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get loss => 'loss';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String madeWithLove(Object myGithub) {
|
|
||||||
return 'Erstellt mit ❤️ von $myGithub';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get manual => 'Handbuch';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get max => 'max';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get maxRetryCount => 'Anzahl an Verbindungsversuchen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get maxRetryCountEqual0 =>
|
|
||||||
'Unbegrenzte Verbindungsversuche zum Server';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get min => 'min';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get mission => 'Mission';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get more => 'Mehr';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get moveOutServerFuncBtnsHelp =>
|
|
||||||
'Ein: kann unter jeder Karte auf der Registerkarte \"Server\" angezeigt werden. Aus: kann oben auf der Seite \"Serverdetails\" angezeigt werden.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ms => 'ms';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get needHomeDir =>
|
|
||||||
'Wenn Sie ein Synology-Benutzer sind, [sehen Sie hier](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Benutzer anderer Systeme müssen suchen, wie man ein Home-Verzeichnis erstellt.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get needRestart => 'App muss neugestartet werden';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get net => 'Netzwerk';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get netViewType => 'Netzwerkansicht Typ';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get newContainer => 'Neuer Container';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noLineChart => 'Verwenden Sie keine Liniendiagramme';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noLineChartForCpu => 'Verwenden Sie keine Liniendiagramme für CPU';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noPrivateKeyTip =>
|
|
||||||
'Der private Schlüssel existiert nicht, möglicherweise wurde er gelöscht oder es liegt ein Konfigurationsfehler vor.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noPromptAgain => 'Nicht mehr nachfragen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get node => 'Knoten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get notAvailable => 'Nicht verfügbar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onServerDetailPage => 'in Detailansicht des Servers';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onlyOneLine => 'Nur als eine Zeile anzeigen (scrollbar)';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onlyWhenCoreBiggerThan8 =>
|
|
||||||
'Wirksam nur, wenn die Anzahl der Kerne > 8 ist.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get openLastPath => 'Öffnen Sie den letzten Pfad';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get openLastPathTip =>
|
|
||||||
'Verschiedene Server haben unterschiedliche Einträge, und der Eintrag ist der Pfad zum Ausgang';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get parseContainerStatsTip =>
|
|
||||||
'Das Analysieren des Belegungsstatus durch Docker ist relativ langsam';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String percentOfSize(Object percent, Object size) {
|
|
||||||
return '$percent% von $size';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get permission => 'Berechtigungen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingAvg => 'Avg:';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingInputIP => 'Bitte gib eine Ziel-IP/Domain ein.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingNoServer =>
|
|
||||||
'Kein Server zum Anpingen.\nBitte füge einen Server hinzu.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pkg => 'Pkg';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get plugInType => 'Einfügetyp';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get port => 'Port';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get preferDiskAmount => 'Festplattenkapazität vorrangig anzeigen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get preview => 'Vorschau';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get privateKey => 'Private Key';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get process => 'Prozess';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get prune => 'Beschneiden';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pushToken => 'Push Token';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveIgnoreCertTip =>
|
|
||||||
'Nicht empfohlen, Achten Sie auf Sicherheitsrisiken! Wenn Sie das Standardzertifikat von PVE verwenden, müssen Sie diese Option aktivieren.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveLoginFailed =>
|
|
||||||
'Anmeldung fehlgeschlagen. Kann nicht mit Benutzername/Passwort aus der Serverkonfiguration angemeldet werden, um sich über Linux PAM anzumelden.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveVersionLow =>
|
|
||||||
'Diese Funktion befindet sich derzeit in der Testphase und wurde nur auf PVE 8+ getestet. Bitte verwenden Sie sie mit Vorsicht.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pwd => 'Passwort';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get read => 'Lesen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get reboot => 'Neustart';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberPwdInMem => 'Passwort im Speicher behalten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberPwdInMemTip => 'Für Container, Aufhängen usw.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberWindowSize => 'Fenstergröße merken';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get remotePath => 'Entfernte Pfade';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get restart => 'Neustart';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get result => 'Result';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rotateAngel => 'Rotationswinkel';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get route => 'Routen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get run => 'Ausführen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get running => 'läuft';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sameIdServerExist =>
|
|
||||||
'Ein Server mit derselben ID existiert bereits';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get save => 'Speichern';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get saved => 'Gerettet';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get second => 's';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sensors => 'Sensor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sequence => 'Sequenz';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get server => 'Server';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverDetailOrder => 'Reihenfolge der Widgets auf der Detailseite';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverFuncBtns => 'Server-Funktionsschaltflächen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverOrder => 'Server-Bestellung';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpDlPrepare => 'Verbindung vorbereiten...';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpEditorTip =>
|
|
||||||
'Wenn leer, verwenden Sie den im App integrierten Dateieditor. Wenn ein Wert vorhanden ist, wird der Editor des Remote-Servers verwendet, z.B. `vim` (es wird empfohlen, automatisch gemäß `EDITOR` zu ermitteln).';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpRmrDirSummary =>
|
|
||||||
'Verwenden Sie \"rm -r\", um das Verzeichnis in SFTP zu löschen.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpSSHConnected => 'SFTP Verbunden';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpShowFoldersFirst => 'Ordner zuerst anzeigen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get showDistLogo => 'Distributionslogo anzeigen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get shutdown => 'Abschaltung';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get size => 'Größe';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get snippet => 'Snippet';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get softWrap => 'Weicher Umbruch';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get specifyDev => 'Gerät angeben';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get specifyDevTip =>
|
|
||||||
'Zum Beispiel bezieht sich die Standard-Netzwerkverkehrsstatistik auf alle Geräte. Hier können Sie ein bestimmtes Gerät angeben.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get speed => 'Tempo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String spentTime(Object time) {
|
|
||||||
return 'Benötigte Zeit: $time';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sshTermHelp =>
|
|
||||||
'Wenn das Terminal scrollbar ist, kann durch horizontales Ziehen Text ausgewählt werden. Durch Klicken auf die Tastentaste wird die Tastatur ein- oder ausgeschaltet. Das Dateisymbol öffnet den aktuellen Pfad SFTP. Die Zwischenablage-Schaltfläche kopiert den Inhalt, wenn Text ausgewählt ist, und fügt Inhalte aus der Zwischenablage in das Terminal ein, wenn kein Text ausgewählt ist und Inhalte in der Zwischenablage vorhanden sind. Das Codesymbol fügt Code-Schnipsel ins Terminal ein und führt sie aus.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String sshTip(Object url) {
|
|
||||||
return 'Diese Funktion befindet sich jetzt in der Experimentierphase.\n\nBitte melde Bugs auf $url oder mach mit bei der Entwicklung.';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sshVirtualKeyAutoOff =>
|
|
||||||
'Automatische Umschaltung der virtuellen Tasten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get start => 'Start';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stat => 'Statistik';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stats => 'Statistik';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stop => 'Stop';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stopped => 'Ausgelaufen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get storage => 'Speicher';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get supportFmtArgs =>
|
|
||||||
'Die folgenden Formatierungsparameter werden unterstützt:';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get suspend => 'Suspend';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get suspendTip =>
|
|
||||||
'Die Suspend-Funktion erfordert Root-Rechte und systemd-Unterstützung.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String switchTo(Object val) {
|
|
||||||
return 'Wechseln zu $val';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sync => 'Sync';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get syncTip =>
|
|
||||||
'Damit einige Änderungen wirksam werden, kann ein Neustart erforderlich sein.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get system => 'Systeme';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get tag => 'Tags';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get temperature => 'Temperatur';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get termFontSizeTip =>
|
|
||||||
'Diese Einstellung beeinflusst die Größe des Terminals (Breite und Höhe). Sie können die Terminalseite zoomen, um die Schriftgröße der aktuellen Sitzung anzupassen.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get terminal => 'Terminal';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get test => 'Prüfung';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get textScaler => 'Skalierung der Schriftart';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get textScalerTip =>
|
|
||||||
'1.0 => 100% (Originalgröße), funktioniert nur auf der Serverseite Teil der Schrift, nicht empfohlen zu ändern.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get theme => 'Themen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get time => 'Zeit';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get times => 'x';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get total => 'Total';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get traffic => 'Durchflussmenge';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get trySudo => 'Versuche es mit sudo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ttl => 'TTL';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get unknown => 'Unbekannt';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get unkownConvertMode => 'Unbekannter Konvertierungsmodus';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get update => 'Update';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get updateIntervalEqual0 =>
|
|
||||||
'Wenn du den Wert 0 einstellst, wird nicht automatisch aktualisiert.\nDer CPU-Status kann nicht berechnet werden.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get updateServerStatusInterval =>
|
|
||||||
'Aktualisierungsintervall des Serverstatus';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get upload => 'Hochladen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get upsideDown => 'Upside Down';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get uptime => 'Betriebszeit';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useCdn => 'Verwenden von CDN';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useCdnTip =>
|
|
||||||
'Nicht-chinesischen Benutzern wird die Verwendung eines CDN empfohlen. Möchten Sie es verwenden?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useNoPwd => 'Es wird kein Passwort verwendet';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get usePodmanByDefault => 'Standardmäßige Verwendung von Podman';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get used => 'Gebraucht';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get view => 'Ansicht';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get viewErr => 'Fehler anzeigen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpClipboard =>
|
|
||||||
'In die Zwischenablage kopieren, wenn das ausgewählte Terminal nicht leer ist, andernfalls den Inhalt der Zwischenablage in das Terminal einfügen.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpIME => 'Tastatur ein-/ausschalten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpSFTP => 'Aktuelles Verzeichnis in SFTP öffnen.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get waitConnection =>
|
|
||||||
'Bitte warte, bis die Verbindung hergestellt wurde.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get wakeLock => 'Wach halten';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get watchNotPaired => 'Keine gekoppelte Apple Watch';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get webdavSettingEmpty => 'Webdav-Einstellungen sind leer';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get whenOpenApp => 'Beim Öffnen der App';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get wolTip =>
|
|
||||||
'Nach der Konfiguration von WOL (Wake-on-LAN) wird jedes Mal, wenn der Server verbunden wird, eine WOL-Anfrage gesendet.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get write => 'Schreiben';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get writeScriptFailTip =>
|
|
||||||
'Das Schreiben des Skripts ist fehlgeschlagen, möglicherweise aufgrund fehlender Berechtigungen oder das Verzeichnis existiert nicht.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get writeScriptTip =>
|
|
||||||
'Nach der Verbindung mit dem Server wird ein Skript in ~/.config/server_box geschrieben, um den Systemstatus zu überwachen. Sie können den Skriptinhalt überprüfen.';
|
|
||||||
}
|
|
||||||
@@ -1,773 +0,0 @@
|
|||||||
// ignore: unused_import
|
|
||||||
import 'package:intl/intl.dart' as intl;
|
|
||||||
import 'l10n.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
|
|
||||||
/// The translations for English (`en`).
|
|
||||||
class AppLocalizationsEn extends AppLocalizations {
|
|
||||||
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get aboutThanks =>
|
|
||||||
'Thanks to the following people who participated in.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get acceptBeta => 'Accept beta version updates';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get addSystemPrivateKeyTip =>
|
|
||||||
'Currently private keys don\'t exist, do you want to add the one that comes with the system (~/.ssh/id_rsa)?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get added2List => 'Added to task list';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get addr => 'Address';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get alreadyLastDir => 'Already in last directory.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get authFailTip =>
|
|
||||||
'Authentication failed, please check whether credentials are correct';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoBackupConflict =>
|
|
||||||
'Only one automatic backup can be turned on at the same time.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoConnect => 'Auto connect';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoRun => 'Auto run';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoUpdateHomeWidget => 'Automatic home widget update';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupTip =>
|
|
||||||
'The exported data is weakly encrypted. \nPlease keep it safe.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupVersionNotMatch => 'Backup version is not match.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get battery => 'Battery';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get bgRun => 'Run in background';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get bgRunTip =>
|
|
||||||
'This switch only means the program will try to run in the background. Whether it can run in the background depends on whether the permission is enabled or not. For AOSP-based Android ROMs, please disable \"Battery Optimization\" in this app. For MIUI / HyperOS, please change the power saving policy to \"Unlimited\".';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get closeAfterSave => 'Save and close';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cmd => 'Command';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get collapseUITip =>
|
|
||||||
'Whether to collapse long lists present in the UI by default';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get conn => 'Connection';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get container => 'Container';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get containerTrySudoTip =>
|
|
||||||
'For example: In the app, the user is set to aaa, but Docker is installed under the root user. In this case, you need to enable this option.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get convert => 'Convert';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get copyPath => 'Copy path';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cpuViewAsProgressTip =>
|
|
||||||
'Display the usage of each CPU in a progress bar style (old style)';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cursorType => 'Cursor type';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmd => 'Custom commands';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmdDocUrl =>
|
|
||||||
'https://github.com/lollipopkit/flutter_server_box/wiki#custom-commands';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmdHint => '\"Command Name\": \"Command\"';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get decode => 'Decode';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get decompress => 'Decompress';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get deleteServers => 'Batch delete servers';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get desktopTerminalTip =>
|
|
||||||
'Command used to open the terminal emulator when launching SSH sessions.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dirEmpty => 'Make sure the folder is empty.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get disconnected => 'Disconnected';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get disk => 'Disk';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get diskHealth => 'Disk Health';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get diskIgnorePath => 'Ignore path for disk';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get displayCpuIndex => 'Display CPU index';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dl2Local(Object fileName) {
|
|
||||||
return 'Download $fileName to local?';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dockerEmptyRunningItems =>
|
|
||||||
'There are no running containers.\nThis could be because:\n- The Docker installation user is not the same as the username configured within the App.\n- The environment variable DOCKER_HOST was not read correctly. You can get it by running `echo \$DOCKER_HOST` in the terminal.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerImagesFmt(Object count) {
|
|
||||||
return '$count images';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dockerNotInstalled => 'Docker not installed';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerStatusRunningAndStoppedFmt(
|
|
||||||
Object runningCount,
|
|
||||||
Object stoppedCount,
|
|
||||||
) {
|
|
||||||
return '$runningCount running, $stoppedCount container stopped.';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerStatusRunningFmt(Object count) {
|
|
||||||
return '$count container running.';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get doubleColumnMode => 'Double column mode';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get doubleColumnTip =>
|
|
||||||
'This option only enables the feature, whether it can actually be enabled depends on the width of the device';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editVirtKeys => 'Edit virtual keys';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editor => 'Editor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editorHighlightTip =>
|
|
||||||
'The current code highlighting performance is not ideal and can be optionally turned off to improve.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get emulator => 'Emulator';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get encode => 'Encode';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get envVars => 'Environment variable';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get experimentalFeature => 'Experimental feature';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get extraArgs => 'Extra arguments';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fallbackSshDest => 'Fallback SSH destination';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fdroidReleaseTip =>
|
|
||||||
'If you downloaded this app from F-Droid, it is recommended to turn off this option.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fgService => 'Foreground Service';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fgServiceTip =>
|
|
||||||
'After enabling, some device models may crash. Disabling it may cause some models to be unable to maintain SSH connections in the background. Please allow ServerBox notification permissions, background running, and self-wake-up in system settings.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
|
||||||
return 'File \'$file\' too large $size, max $sizeMax';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get followSystem => 'Follow system';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get font => 'Font';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fontSize => 'Font size';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get force => 'Force';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreen => 'Full screen mode';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenJitter => 'Full screen jitter';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenJitterHelp => 'To avoid screen burn-in';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenTip =>
|
|
||||||
'Should full-screen mode be enabled when the device is rotated to landscape mode? This option only applies to the server tab.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get goBackQ => 'Go back?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get goto => 'Go to';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get hideTitleBar => 'Hide title bar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get highlight => 'Code highlighting';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get homeWidgetUrlConfig => 'Config home widget url';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get host => 'Host';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String httpFailedWithCode(Object code) {
|
|
||||||
return 'request failed, status code: $code';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ignoreCert => 'Ignore certificate';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get image => 'Image';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get imagesList => 'Images list';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get init => 'Initialize';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get inner => 'Inner';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get install => 'install';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get installDockerWithUrl =>
|
|
||||||
'Please https://docs.docker.com/engine/install docker first.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get invalid => 'Invalid';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get jumpServer => 'Jump server';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepForeground => 'Keep app foreground!';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepStatusWhenErr => 'Preserve the last server state';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepStatusWhenErrTip =>
|
|
||||||
'Only in the event of an error during script execution';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keyAuth => 'Key Auth';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get letterCache => 'Letter caching';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get letterCacheTip =>
|
|
||||||
'Recommended to disable, but after disabling, it will be impossible to input CJK characters.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get license => 'License';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get location => 'Location';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get loss => 'loss';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String madeWithLove(Object myGithub) {
|
|
||||||
return 'Made with ❤️ by $myGithub';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get manual => 'Manual';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get max => 'max';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get maxRetryCount => 'Number of server reconnections';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get maxRetryCountEqual0 => 'Will retry again and again.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get min => 'min';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get mission => 'Mission';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get more => 'More';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get moveOutServerFuncBtnsHelp =>
|
|
||||||
'On: can be displayed below each card on the Server Tab page. Off: can be displayed at the top of the Server Details page.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ms => 'ms';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get needHomeDir =>
|
|
||||||
'If you are a Synology user, [see here](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Users of other systems need to search for how to create a home directory.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get needRestart => 'App needs to be restarted';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get net => 'Network';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get netViewType => 'Network view type';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get newContainer => 'New container';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noLineChart => 'Do not use line charts';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noLineChartForCpu => 'Do not use line charts for CPU';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noPrivateKeyTip =>
|
|
||||||
'The private key does not exist, it may have been deleted or there is a configuration error.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noPromptAgain => 'Do not prompt again';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get node => 'Node';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get notAvailable => 'Unavailable';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onServerDetailPage => 'On server detail page';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onlyOneLine => 'Only display as one line (scrollable)';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onlyWhenCoreBiggerThan8 =>
|
|
||||||
'Works only when the number of cores is greater than 8';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get openLastPath => 'Open the last path';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get openLastPathTip =>
|
|
||||||
'Different servers will have different logs, and the log is the path to the exit';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get parseContainerStatsTip =>
|
|
||||||
'Parsing the occupancy status of Docker is relatively slow.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String percentOfSize(Object percent, Object size) {
|
|
||||||
return '$percent% of $size';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get permission => 'Permissions';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingAvg => 'Avg:';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingInputIP => 'Please input a target IP / domain.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingNoServer =>
|
|
||||||
'No server to ping.\nPlease add a server in server tab.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pkg => 'Pkg';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get plugInType => 'Insertion Type';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get port => 'Port';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get preferDiskAmount => 'Prioritize displaying disk capacity';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get preview => 'Preview';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get privateKey => 'Private Key';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get process => 'Process';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get prune => 'Prune';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pushToken => 'Push token';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveIgnoreCertTip =>
|
|
||||||
'Not recommended to enable, beware of security risks! If you are using the default certificate from PVE, you need to enable this option.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveLoginFailed =>
|
|
||||||
'Login failed. Unable to authenticate with username/password from server configuration for Linux PAM login.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveVersionLow =>
|
|
||||||
'This feature is currently in the testing phase and has only been tested on PVE 8+. Please use it with caution.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pwd => 'Password';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get read => 'Read';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get reboot => 'Reboot';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberPwdInMem => 'Remember password in memory';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberPwdInMemTip => 'Used for containers, suspending, etc.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberWindowSize => 'Remember window size';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get remotePath => 'Remote path';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get restart => 'Restart';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get result => 'Result';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rotateAngel => 'Rotation angle';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get route => 'Routing';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get run => 'Run';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get running => 'Running';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sameIdServerExist => 'A server with the same ID already exists';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get save => 'Save';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get saved => 'Saved';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get second => 's';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sensors => 'Sensor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sequence => 'Sequence';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get server => 'Server';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverDetailOrder => 'Detail page widget order';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverFuncBtns => 'Server function buttons';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverOrder => 'Server order';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpDlPrepare => 'Preparing to connect...';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpEditorTip =>
|
|
||||||
'If empty, use the built-in file editor of the app. If a value is present, use the remote server’s editor, e.g., `vim` (recommended to automatically detect according to `EDITOR`).';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpRmrDirSummary => 'Use `rm -r` to delete a folder in SFTP.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpSSHConnected => 'SFTP Connected';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpShowFoldersFirst => 'Display folders first';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get showDistLogo => 'Show distribution logo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get shutdown => 'Shutdown';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get size => 'Size';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get snippet => 'Snippet';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get softWrap => 'Soft wrap';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get specifyDev => 'Specify device';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get specifyDevTip =>
|
|
||||||
'For example, network traffic statistics are by default for all devices. You can specify a particular device here.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get speed => 'Speed';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String spentTime(Object time) {
|
|
||||||
return 'Spent time: $time';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sshTermHelp =>
|
|
||||||
'When the terminal is scrollable, dragging horizontally can select text. Clicking the keyboard button turns the keyboard on/off. The file icon opens the current path SFTP. The clipboard button copies the content when text is selected, and pastes content from the clipboard into the terminal when no text is selected and there is content on the clipboard. The code icon pastes code snippets into the terminal and executes them.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String sshTip(Object url) {
|
|
||||||
return 'This function is now in the experimental stage.\n\nPlease report bugs on $url or join our development.';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sshVirtualKeyAutoOff => 'Auto switching of virtual keys';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get start => 'Start';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stat => 'Statistics';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stats => 'Statistics';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stop => 'Stop';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stopped => 'Stopped';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get storage => 'Storage';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get supportFmtArgs =>
|
|
||||||
'The following formatting parameters are supported:';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get suspend => 'Suspend';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get suspendTip =>
|
|
||||||
'The suspend function requires root permission and systemd support.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String switchTo(Object val) {
|
|
||||||
return 'Switch to $val';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sync => 'Sync';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get syncTip =>
|
|
||||||
'A restart may be required for some changes to take effect.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get system => 'System';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get tag => 'Tags';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get temperature => 'Temperature';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get termFontSizeTip =>
|
|
||||||
'This setting will affect the terminal size (width and height). You can zoom in on the terminal page to adjust the font size of the current session.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get terminal => 'Terminal';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get test => 'Test';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get textScaler => 'Text scaler';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get textScalerTip =>
|
|
||||||
'1.0 => 100% (original size), only works on server page part of the font, not recommended to change.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get theme => 'Theme';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get time => 'Time';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get times => 'Times';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get total => 'Total';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get traffic => 'Traffic';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get trySudo => 'Try using sudo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ttl => 'TTL';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get unknown => 'Unknown';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get unkownConvertMode => 'Unknown conversion mode';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get update => 'Update';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get updateIntervalEqual0 =>
|
|
||||||
'You set to 0, will not update automatically.\nCan\'t calculate CPU status.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get updateServerStatusInterval => 'Server status update interval';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get upload => 'Upload';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get upsideDown => 'Upside Down';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get uptime => 'Uptime';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useCdn => 'Using CDN';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useCdnTip =>
|
|
||||||
'Non-Chinese users are recommended to use CDN. Would you like to use it?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useNoPwd => 'No password will be used';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get usePodmanByDefault => 'Use Podman by default';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get used => 'Used';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get view => 'View';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get viewErr => 'See error';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpClipboard =>
|
|
||||||
'Copy to the clipboard if the selected terminal is not empty, otherwise paste the content of the clipboard to the terminal.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpIME => 'Turn on/off the keyboard';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpSFTP => 'Open current directory in SFTP.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get waitConnection =>
|
|
||||||
'Please wait for the connection to be established.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get wakeLock => 'Keep awake';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get watchNotPaired => 'No paired Apple Watch';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get webdavSettingEmpty => 'WebDav setting is empty';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get whenOpenApp => 'When opening the app';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get wolTip =>
|
|
||||||
'After configuring WOL (Wake-on-LAN), a WOL request is sent each time the server is connected.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get write => 'Write';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get writeScriptFailTip =>
|
|
||||||
'Writing to the script failed, possibly due to lack of permissions or the directory does not exist.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get writeScriptTip =>
|
|
||||||
'After connecting to the server, a script will be written to ~/.config/server_box to monitor the system status. You can review the script content.';
|
|
||||||
}
|
|
||||||
@@ -1,781 +0,0 @@
|
|||||||
// ignore: unused_import
|
|
||||||
import 'package:intl/intl.dart' as intl;
|
|
||||||
import 'l10n.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
|
|
||||||
/// The translations for Spanish Castilian (`es`).
|
|
||||||
class AppLocalizationsEs extends AppLocalizations {
|
|
||||||
AppLocalizationsEs([String locale = 'es']) : super(locale);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get aboutThanks => 'Gracias a los siguientes participantes.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get acceptBeta => 'Aceptar actualizaciones de la versión de prueba';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get addSystemPrivateKeyTip =>
|
|
||||||
'Actualmente no hay ninguna llave privada, ¿quieres agregar la que viene por defecto en el sistema (~/.ssh/id_rsa)?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get added2List => 'Añadido a la lista de tareas';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get addr => 'Dirección';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get alreadyLastDir => 'Ya estás en el directorio superior';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get authFailTip =>
|
|
||||||
'La autenticación ha fallado, por favor verifica si la contraseña/llave/host/usuario, etc., son incorrectos.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoBackupConflict =>
|
|
||||||
'Solo se puede activar una copia de seguridad automática a la vez';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoConnect => 'Conexión automática';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoRun => 'Ejecución automática';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get autoUpdateHomeWidget =>
|
|
||||||
'Actualizar automáticamente el widget del escritorio';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupTip =>
|
|
||||||
'Los datos exportados solo están encriptados de manera básica, por favor guárdalos en un lugar seguro.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get backupVersionNotMatch =>
|
|
||||||
'La versión de la copia de seguridad no coincide, no se puede restaurar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get battery => 'Batería';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get bgRun => 'Ejecución en segundo plano';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get bgRunTip =>
|
|
||||||
'Este interruptor solo indica que la aplicación intentará correr en segundo plano, si puede hacerlo o no depende de si tiene el permiso correspondiente. En Android puro, por favor desactiva la “optimización de batería” para esta app, en MIUI por favor cambia la estrategia de ahorro de energía a “Sin restricciones”.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get closeAfterSave => 'Guardar y cerrar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cmd => 'Comando';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get collapseUITip =>
|
|
||||||
'¿Colapsar por defecto las listas largas en la UI?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get conn => 'Conectar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get container => 'Contenedor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get containerTrySudoTip =>
|
|
||||||
'Por ejemplo: si configuras el usuario dentro de la app como aaa, pero Docker está instalado bajo el usuario root, entonces necesitarás habilitar esta opción';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get convert => 'Convertir';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get copyPath => 'Copiar ruta';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cpuViewAsProgressTip =>
|
|
||||||
'Muestre la tasa de uso de cada CPU en estilo de barra de progreso (estilo antiguo)';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get cursorType => 'Tipo de cursor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmd => 'Comandos personalizados';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmdDocUrl =>
|
|
||||||
'https://github.com/lollipopkit/flutter_server_box/wiki#custom-commands';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get customCmdHint => '\"Nombre del comando\": \"Comando\"';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get decode => 'Decodificar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get decompress => 'Descomprimir';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get deleteServers => 'Eliminar servidores en lote';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get desktopTerminalTip =>
|
|
||||||
'Comando utilizado para abrir el emulador de terminal al iniciar sesiones SSH.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dirEmpty => 'Asegúrate de que el directorio esté vacío';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get disconnected => 'Desconectado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get disk => 'Disco';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get diskHealth => 'Salud del disco';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get diskIgnorePath => 'Rutas de disco ignoradas';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get displayCpuIndex => 'Muestre el índice de CPU';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dl2Local(Object fileName) {
|
|
||||||
return '¿Descargar $fileName a local?';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dockerEmptyRunningItems =>
|
|
||||||
'No hay contenedores en ejecución.\nEsto podría deberse a que:\n- El usuario con el que se instaló Docker es diferente al configurado en la app\n- La variable de entorno DOCKER_HOST no se ha leído correctamente. Puedes obtenerla ejecutando `echo \$DOCKER_HOST` en el terminal.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerImagesFmt(Object count) {
|
|
||||||
return 'Total de $count imágenes';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get dockerNotInstalled => 'Docker no está instalado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerStatusRunningAndStoppedFmt(
|
|
||||||
Object runningCount,
|
|
||||||
Object stoppedCount,
|
|
||||||
) {
|
|
||||||
return '$runningCount en ejecución, $stoppedCount detenidos';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String dockerStatusRunningFmt(Object count) {
|
|
||||||
return '$count contenedores en ejecución';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get doubleColumnMode => 'Modo de doble columna';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get doubleColumnTip =>
|
|
||||||
'Esta opción solo habilita la función, si se puede activar o no depende del ancho del dispositivo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editVirtKeys => 'Editar teclas virtuales';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editor => 'Editor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get editorHighlightTip =>
|
|
||||||
'El rendimiento del resaltado de código es bastante pobre actualmente, puedes elegir desactivarlo para mejorar.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get emulator => 'Emulador';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get encode => 'Codificar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get envVars => 'Variable de entorno';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get experimentalFeature => 'Función experimental';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get extraArgs => 'Argumentos extra';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fallbackSshDest => 'Destino SSH alternativo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fdroidReleaseTip =>
|
|
||||||
'Si descargaste esta aplicación desde F-Droid, se recomienda desactivar esta opción.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fgService => 'Servicio en primer plano';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fgServiceTip =>
|
|
||||||
'Después de activarlo, algunos modelos de dispositivos pueden bloquearse. Desactivarlo puede hacer que algunos modelos no puedan mantener las conexiones SSH en segundo plano. Por favor, permita los permisos de notificación de ServerBox, la ejecución en segundo plano y el auto-despertar en la configuración del sistema.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String fileTooLarge(Object file, Object size, Object sizeMax) {
|
|
||||||
return 'El archivo \'$file\' es demasiado grande \'$size\', supera el $sizeMax';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get followSystem => 'Seguir al sistema';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get font => 'Fuente';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fontSize => 'Tamaño de fuente';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get force => 'Forzar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreen => 'Modo pantalla completa';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenJitter => 'Temblores en modo pantalla completa';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenJitterHelp => 'Prevención de quemaduras de pantalla';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get fullScreenTip =>
|
|
||||||
'¿Debe habilitarse el modo de pantalla completa cuando el dispositivo se rote al modo horizontal? Esta opción solo se aplica a la pestaña del servidor.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get goBackQ => '¿Regresar?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get goto => 'Ir a';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get hideTitleBar => 'Ocultar barra de título';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get highlight => 'Resaltar código';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get homeWidgetUrlConfig => 'Configuración de URL del widget de inicio';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get host => 'Anfitrión';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String httpFailedWithCode(Object code) {
|
|
||||||
return 'Fallo en la solicitud, código de estado: $code';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ignoreCert => 'Ignorar certificado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get image => 'Imagen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get imagesList => 'Lista de imágenes';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get init => 'Inicializar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get inner => 'Interno';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get install => 'Instalar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get installDockerWithUrl =>
|
|
||||||
'Por favor instala Docker primero desde https://docs.docker.com/engine/install';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get invalid => 'Inválido';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get jumpServer => 'Servidor de salto';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepForeground => '¡Por favor, mantén la app en primer plano!';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepStatusWhenErr => 'Mantener el estado anterior del servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keepStatusWhenErrTip =>
|
|
||||||
'Solo aplica cuando hay errores al ejecutar scripts';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get keyAuth => 'Autenticación con llave';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get letterCache => 'Caché de letras';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get letterCacheTip =>
|
|
||||||
'Recomendado desactivar, pero después de desactivarlo, no se podrán ingresar caracteres CJK.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get license => 'Licencia de código abierto';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get location => 'Ubicación';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get loss => 'Tasa de pérdida';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String madeWithLove(Object myGithub) {
|
|
||||||
return 'Hecho con ❤️ por $myGithub';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get manual => 'Manual';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get max => 'Máximo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get maxRetryCount =>
|
|
||||||
'Número máximo de reintentos de conexión al servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get maxRetryCountEqual0 => 'Reintentará infinitamente';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get min => 'Mínimo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get mission => 'Misión';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get more => 'Más';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get moveOutServerFuncBtnsHelp =>
|
|
||||||
'Activado: se mostrará debajo de cada tarjeta en la página de servidores. Desactivado: se mostrará en la parte superior de los detalles del servidor.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ms => 'milisegundos';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get needHomeDir =>
|
|
||||||
'Si eres usuario de Synology, [consulta aquí](https://kb.synology.com/DSM/tutorial/user_enable_home_service). Los usuarios de otros sistemas deben buscar cómo crear un directorio home.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get needRestart => 'Necesita reiniciar la app';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get net => 'Red';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get netViewType => 'Tipo de vista de red';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get newContainer => 'Crear contenedor nuevo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noLineChart => 'No utilice gráficos de líneas';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noLineChartForCpu => 'No utilice gráficos lineales para la CPU';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noPrivateKeyTip =>
|
|
||||||
'La clave privada no existe, puede haber sido eliminada o hay un error de configuración.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get noPromptAgain => 'No volver a preguntar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get node => 'Nodo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get notAvailable => 'No disponible';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onServerDetailPage => 'En la página de detalles del servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onlyOneLine => 'Mostrar solo en una línea (desplazable)';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get onlyWhenCoreBiggerThan8 =>
|
|
||||||
'Efectivo solo cuando el número de núcleos > 8';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get openLastPath => 'Abrir el último camino';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get openLastPathTip =>
|
|
||||||
'Los diferentes servidores tendrán diferentes registros, y lo que se registra es la ruta de salida';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get parseContainerStatsTip =>
|
|
||||||
'El análisis del estado de uso de Docker es bastante lento';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String percentOfSize(Object percent, Object size) {
|
|
||||||
return 'El $percent% de $size';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get permission => 'Permisos';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingAvg => 'Promedio:';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingInputIP =>
|
|
||||||
'Por favor, introduce la IP de destino o el dominio';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pingNoServer =>
|
|
||||||
'No hay servidores disponibles para hacer Ping\nPor favor, añade un servidor en la pestaña de servidores y vuelve a intentarlo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pkg => 'Gestión de paquetes';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get plugInType => 'Tipo de inserción';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get port => 'Puerto';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get preferDiskAmount =>
|
|
||||||
'Priorizar la visualización de la capacidad del disco';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get preview => 'Vista previa';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get privateKey => 'Llave privada';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get process => 'Proceso';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get prune => 'Podar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pushToken => 'Token de notificaciones';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveIgnoreCertTip =>
|
|
||||||
'No se recomienda activarlo, ¡tenga cuidado con los riesgos de seguridad! Si está utilizando el certificado predeterminado de PVE, debe habilitar esta opción.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveLoginFailed =>
|
|
||||||
'Fallo al iniciar sesión. No se puede autenticar con el nombre de usuario/contraseña de la configuración del servidor para el inicio de sesión de Linux PAM.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pveVersionLow =>
|
|
||||||
'Esta función está actualmente en fase de prueba y solo se ha probado en PVE 8+. Úsela con precaución.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get pwd => 'Contraseña';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get read => 'Leer';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get reboot => 'Reiniciar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberPwdInMem => 'Recordar contraseña en la memoria';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberPwdInMemTip =>
|
|
||||||
'Utilizado para contenedores, suspensión, etc.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rememberWindowSize => 'Recordar el tamaño de la ventana';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get remotePath => 'Ruta remota';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get restart => 'Reiniciar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get result => 'Resultado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get rotateAngel => 'Ángulo de rotación';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get route => 'Enrutamiento';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get run => 'Ejecutar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get running => 'En ejecución';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sameIdServerExist => 'Ya existe un servidor con el mismo ID';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get save => 'Guardar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get saved => 'Guardado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get second => 'Segundo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sensors => 'Sensores';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sequence => 'Secuencia';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get server => 'Servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverDetailOrder =>
|
|
||||||
'Orden de los componentes en la página de detalles del servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverFuncBtns => 'Botones de función del servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get serverOrder => 'Orden del servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpDlPrepare => 'Preparando para conectar al servidor...';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpEditorTip =>
|
|
||||||
'Si está vacío, use el editor de archivos incorporado de la aplicación. Si hay un valor, use el editor del servidor remoto, por ejemplo, `vim` (se recomienda detectar automáticamente según `EDITOR`).';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpRmrDirSummary =>
|
|
||||||
'Usar `rm -r` en SFTP para eliminar directorios';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpSSHConnected => 'SFTP conectado...';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sftpShowFoldersFirst => 'Mostrar carpetas primero';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get showDistLogo => 'Mostrar logo de distribución';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get shutdown => 'Apagar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get size => 'Tamaño';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get snippet => 'Fragmento de código';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get softWrap => 'Salto de línea suave';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get specifyDev => 'Especificar dispositivo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get specifyDevTip =>
|
|
||||||
'Por ejemplo, las estadísticas de tráfico de red son por defecto para todos los dispositivos. Aquí puede especificar un dispositivo en particular.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get speed => 'Velocidad';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String spentTime(Object time) {
|
|
||||||
return 'Tiempo gastado: $time';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sshTermHelp =>
|
|
||||||
'Cuando el terminal es desplazable, arrastrar horizontalmente puede seleccionar texto. Hacer clic en el botón del teclado enciende/apaga el teclado. El icono de archivo abre el SFTP de la ruta actual. El botón del portapapeles copia el contenido cuando se selecciona texto y pega el contenido del portapapeles en el terminal cuando no se selecciona texto y hay contenido en el portapapeles. El icono de código pega fragmentos de código en el terminal y los ejecuta.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String sshTip(Object url) {
|
|
||||||
return 'Esta función está en fase de pruebas.\n\nPor favor, informa los problemas en $url, o únete a nuestro desarrollo.';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sshVirtualKeyAutoOff =>
|
|
||||||
'Desactivación automática de teclas virtuales';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get start => 'Iniciar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stat => 'Estadísticas';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stats => 'Estadísticas';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stop => 'Detener';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get stopped => 'Detenido';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get storage => 'Almacenamiento';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get supportFmtArgs => 'Soporta los siguientes argumentos de formato:';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get suspend => 'Suspender';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get suspendTip =>
|
|
||||||
'La función de suspender necesita permisos de root y soporte de systemd.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String switchTo(Object val) {
|
|
||||||
return 'Cambiar a $val';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get sync => 'Sincronizar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get syncTip =>
|
|
||||||
'Puede que necesites reiniciar para que algunos cambios tengan efecto.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get system => 'Sistema';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get tag => 'Etiqueta';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get temperature => 'Temperatura';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get termFontSizeTip =>
|
|
||||||
'Este ajuste afectará el tamaño del terminal (ancho y alto). Puedes hacer zoom en la página del terminal para ajustar el tamaño de fuente de la sesión actual.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get terminal => 'Terminal';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get test => 'Prueba';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get textScaler => 'Escalar texto';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get textScalerTip =>
|
|
||||||
'1.0 => 100% (tamaño original), solo afecta a ciertas fuentes en la página del servidor, no se recomienda modificar.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get theme => 'Tema';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get time => 'Tiempo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get times => 'Veces';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get total => 'Total';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get traffic => 'Tráfico';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get trySudo => 'Intentar con sudo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get ttl => 'TTL';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get unknown => 'Desconocido';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get unkownConvertMode => 'Modo de conversión desconocido';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get update => 'Actualizar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get updateIntervalEqual0 =>
|
|
||||||
'Si configuras esto a 0, el estado del servidor no se refrescará automáticamente.\nY no se podrá calcular el uso de CPU.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get updateServerStatusInterval =>
|
|
||||||
'Intervalo de actualización del estado del servidor';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get upload => 'Subir';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get upsideDown => 'Invertir arriba por abajo';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get uptime => 'Tiempo de actividad';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useCdn => 'Usando CDN';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useCdnTip =>
|
|
||||||
'Se recomienda a los usuarios no chinos utilizar CDN. ¿Le gustaría utilizarlo?';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get useNoPwd => 'Se usará sin contraseña';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get usePodmanByDefault => 'Usar Podman por defecto';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get used => 'Usado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get view => 'Vista';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get viewErr => 'Ver error';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpClipboard =>
|
|
||||||
'Si el terminal tiene caracteres seleccionados, entonces copiará los caracteres seleccionados al portapapeles, de lo contrario, pegará el contenido del portapapeles al terminal.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpIME => 'Encender/apagar el teclado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get virtKeyHelpSFTP => 'Abrir la ruta actual en SFTP.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get waitConnection =>
|
|
||||||
'Por favor, espera a que la conexión se establezca';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get wakeLock => 'Mantener despierto';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get watchNotPaired => 'No hay un Apple Watch emparejado';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get webdavSettingEmpty => 'La configuración de Webdav está vacía';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get whenOpenApp => 'Al abrir la App';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get wolTip =>
|
|
||||||
'Después de configurar WOL (Wake-on-LAN), se envía una solicitud de WOL cada vez que se conecta el servidor.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get write => 'Escribir';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get writeScriptFailTip =>
|
|
||||||
'La escritura en el script falló, posiblemente por falta de permisos o porque el directorio no existe.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get writeScriptTip =>
|
|
||||||
'Después de conectarse al servidor, se escribirá un script en ~/.config/server_box para monitorear el estado del sistema. Puedes revisar el contenido del script.';
|
|
||||||
}
|
|
||||||