mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
new & fix
- new: switch of sftp `rm -rf` dir - fix: sftp upload - fix: sftp uploading progress - opt.: editor will save content if is editing file
This commit is contained in:
@@ -416,12 +416,6 @@ abstract class S {
|
|||||||
/// **'Download'**
|
/// **'Download'**
|
||||||
String get download;
|
String get download;
|
||||||
|
|
||||||
/// No description provided for @downloadStatus.
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'{percent}% of {size}'**
|
|
||||||
String downloadStatus(Object percent, Object size);
|
|
||||||
|
|
||||||
/// No description provided for @edit.
|
/// No description provided for @edit.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -920,6 +914,12 @@ abstract class S {
|
|||||||
/// **'Path'**
|
/// **'Path'**
|
||||||
String get path;
|
String get path;
|
||||||
|
|
||||||
|
/// No description provided for @percentOfSize.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'{percent}% of {size}'**
|
||||||
|
String percentOfSize(Object percent, Object size);
|
||||||
|
|
||||||
/// No description provided for @pickFile.
|
/// No description provided for @pickFile.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -1154,6 +1154,12 @@ abstract class S {
|
|||||||
/// **'Preparing to connect...'**
|
/// **'Preparing to connect...'**
|
||||||
String get sftpDlPrepare;
|
String get sftpDlPrepare;
|
||||||
|
|
||||||
|
/// No description provided for @sftpRmrfDir.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Use `rm -rf` to delete dir on SFTP'**
|
||||||
|
String get sftpRmrfDir;
|
||||||
|
|
||||||
/// No description provided for @sftpSSHConnected.
|
/// No description provided for @sftpSSHConnected.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|||||||
@@ -171,11 +171,6 @@ class SDe extends S {
|
|||||||
@override
|
@override
|
||||||
String get download => 'Download';
|
String get download => 'Download';
|
||||||
|
|
||||||
@override
|
|
||||||
String downloadStatus(Object percent, Object size) {
|
|
||||||
return '$percent% von $size';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get edit => 'Bearbeiten';
|
String get edit => 'Bearbeiten';
|
||||||
|
|
||||||
@@ -437,6 +432,11 @@ class SDe extends S {
|
|||||||
@override
|
@override
|
||||||
String get path => 'Pfad';
|
String get path => 'Pfad';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String percentOfSize(Object percent, Object size) {
|
||||||
|
return '$percent% von $size';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get pickFile => 'Datei wählen';
|
String get pickFile => 'Datei wählen';
|
||||||
|
|
||||||
@@ -558,6 +558,9 @@ class SDe extends S {
|
|||||||
@override
|
@override
|
||||||
String get sftpDlPrepare => 'Verbindung vorbereiten...';
|
String get sftpDlPrepare => 'Verbindung vorbereiten...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sftpRmrfDir => 'Verwenden Sie `rm -rf`, um das Verzeichnis auf SFTP zu löschen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP Verbunden';
|
String get sftpSSHConnected => 'SFTP Verbunden';
|
||||||
|
|
||||||
|
|||||||
@@ -171,11 +171,6 @@ class SEn extends S {
|
|||||||
@override
|
@override
|
||||||
String get download => 'Download';
|
String get download => 'Download';
|
||||||
|
|
||||||
@override
|
|
||||||
String downloadStatus(Object percent, Object size) {
|
|
||||||
return '$percent% of $size';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get edit => 'Edit';
|
String get edit => 'Edit';
|
||||||
|
|
||||||
@@ -437,6 +432,11 @@ class SEn extends S {
|
|||||||
@override
|
@override
|
||||||
String get path => 'Path';
|
String get path => 'Path';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String percentOfSize(Object percent, Object size) {
|
||||||
|
return '$percent% of $size';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get pickFile => 'Pick file';
|
String get pickFile => 'Pick file';
|
||||||
|
|
||||||
@@ -558,6 +558,9 @@ class SEn extends S {
|
|||||||
@override
|
@override
|
||||||
String get sftpDlPrepare => 'Preparing to connect...';
|
String get sftpDlPrepare => 'Preparing to connect...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sftpRmrfDir => 'Use `rm -rf` to delete dir on SFTP';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP Connected';
|
String get sftpSSHConnected => 'SFTP Connected';
|
||||||
|
|
||||||
|
|||||||
@@ -171,11 +171,6 @@ class SId extends S {
|
|||||||
@override
|
@override
|
||||||
String get download => 'Unduh';
|
String get download => 'Unduh';
|
||||||
|
|
||||||
@override
|
|
||||||
String downloadStatus(Object percent, Object size) {
|
|
||||||
return '$percent% dari $size';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get edit => 'Edit';
|
String get edit => 'Edit';
|
||||||
|
|
||||||
@@ -437,6 +432,11 @@ class SId extends S {
|
|||||||
@override
|
@override
|
||||||
String get path => 'Jalur';
|
String get path => 'Jalur';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String percentOfSize(Object percent, Object size) {
|
||||||
|
return '$percent% dari $size';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get pickFile => 'Pilih file';
|
String get pickFile => 'Pilih file';
|
||||||
|
|
||||||
@@ -558,6 +558,9 @@ class SId extends S {
|
|||||||
@override
|
@override
|
||||||
String get sftpDlPrepare => 'Bersiap untuk terhubung ...';
|
String get sftpDlPrepare => 'Bersiap untuk terhubung ...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sftpRmrfDir => 'Gunakan `rm -rf` untuk menghapus direktori di SFTP';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'Sftp terhubung';
|
String get sftpSSHConnected => 'Sftp terhubung';
|
||||||
|
|
||||||
|
|||||||
@@ -171,11 +171,6 @@ class SZh extends S {
|
|||||||
@override
|
@override
|
||||||
String get download => '下载';
|
String get download => '下载';
|
||||||
|
|
||||||
@override
|
|
||||||
String downloadStatus(Object percent, Object size) {
|
|
||||||
return '$size 的 $percent%';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get edit => '编辑';
|
String get edit => '编辑';
|
||||||
|
|
||||||
@@ -437,6 +432,11 @@ class SZh extends S {
|
|||||||
@override
|
@override
|
||||||
String get path => '路径';
|
String get path => '路径';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String percentOfSize(Object percent, Object size) {
|
||||||
|
return '$size 的 $percent%';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get pickFile => '选择文件';
|
String get pickFile => '选择文件';
|
||||||
|
|
||||||
@@ -558,6 +558,9 @@ class SZh extends S {
|
|||||||
@override
|
@override
|
||||||
String get sftpDlPrepare => '准备连接至服务器...';
|
String get sftpDlPrepare => '准备连接至服务器...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sftpRmrfDir => '在 SFTP 中使用 `rm -rf` 删除文件夹';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP 已连接...';
|
String get sftpSSHConnected => 'SFTP 已连接...';
|
||||||
|
|
||||||
@@ -888,11 +891,6 @@ class SZhTw extends SZh {
|
|||||||
@override
|
@override
|
||||||
String get download => '下載';
|
String get download => '下載';
|
||||||
|
|
||||||
@override
|
|
||||||
String downloadStatus(Object percent, Object size) {
|
|
||||||
return '$size 的 $percent%';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get edit => '編輯';
|
String get edit => '編輯';
|
||||||
|
|
||||||
@@ -1154,6 +1152,11 @@ class SZhTw extends SZh {
|
|||||||
@override
|
@override
|
||||||
String get path => '路徑';
|
String get path => '路徑';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String percentOfSize(Object percent, Object size) {
|
||||||
|
return '$size 的 $percent%';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get pickFile => '選擇文件';
|
String get pickFile => '選擇文件';
|
||||||
|
|
||||||
@@ -1275,6 +1278,9 @@ class SZhTw extends SZh {
|
|||||||
@override
|
@override
|
||||||
String get sftpDlPrepare => '準備連接至服務器...';
|
String get sftpDlPrepare => '準備連接至服務器...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sftpRmrfDir => '在 SFTP 中使用 `rm -rf` 刪除文件夾';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get sftpSSHConnected => 'SFTP 已連接...';
|
String get sftpSSHConnected => 'SFTP 已連接...';
|
||||||
|
|
||||||
|
|||||||
@@ -86,4 +86,4 @@ class SftpReqStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SftpWorkerStatus { preparing, sshConnectted, downloading, finished }
|
enum SftpWorkerStatus { preparing, sshConnectted, loading, finished }
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
import 'package:easy_isolate/easy_isolate.dart';
|
import 'package:easy_isolate/easy_isolate.dart';
|
||||||
import 'package:toolbox/core/utils/misc.dart';
|
|
||||||
import 'package:toolbox/core/utils/server.dart';
|
|
||||||
|
|
||||||
|
import '../../../core/utils/server.dart';
|
||||||
import 'req.dart';
|
import 'req.dart';
|
||||||
|
|
||||||
class SftpWorker {
|
class SftpWorker {
|
||||||
@@ -78,16 +77,14 @@ Future<void> _download(
|
|||||||
final client = await genClient(req.spi, privateKey: req.privateKey);
|
final client = await genClient(req.spi, privateKey: req.privateKey);
|
||||||
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
||||||
|
|
||||||
final remotePath = req.remotePath;
|
await Directory(req.localPath.substring(0, req.localPath.lastIndexOf('/')))
|
||||||
final localPath = req.localPath;
|
|
||||||
await Directory(localPath.substring(0, req.localPath.lastIndexOf('/')))
|
|
||||||
.create(recursive: true);
|
.create(recursive: true);
|
||||||
final local = File(localPath);
|
final local = File(req.localPath);
|
||||||
if (await local.exists()) {
|
if (await local.exists()) {
|
||||||
await local.delete();
|
await local.delete();
|
||||||
}
|
}
|
||||||
final localFile = local.openWrite(mode: FileMode.append);
|
final localFile = local.openWrite(mode: FileMode.append);
|
||||||
final file = await (await client.sftp()).open(remotePath);
|
final file = await (await client.sftp()).open(req.remotePath);
|
||||||
final size = (await file.stat()).size;
|
final size = (await file.stat()).size;
|
||||||
if (size == null) {
|
if (size == null) {
|
||||||
mainSendPort.send(Exception('can not get file size'));
|
mainSendPort.send(Exception('can not get file size'));
|
||||||
@@ -97,7 +94,7 @@ Future<void> _download(
|
|||||||
const defaultChunkSize = 1024 * 1024;
|
const defaultChunkSize = 1024 * 1024;
|
||||||
final chunkSize = size > defaultChunkSize ? defaultChunkSize : size;
|
final chunkSize = size > defaultChunkSize ? defaultChunkSize : size;
|
||||||
mainSendPort.send(size);
|
mainSendPort.send(size);
|
||||||
mainSendPort.send(SftpWorkerStatus.downloading);
|
mainSendPort.send(SftpWorkerStatus.loading);
|
||||||
for (var i = 0; i < size; i += chunkSize) {
|
for (var i = 0; i < size; i += chunkSize) {
|
||||||
final fileData = file.read(length: chunkSize);
|
final fileData = file.read(length: chunkSize);
|
||||||
await for (var form in fileData) {
|
await for (var form in fileData) {
|
||||||
@@ -125,19 +122,23 @@ Future<void> _upload(
|
|||||||
final client = await genClient(req.spi, privateKey: req.privateKey);
|
final client = await genClient(req.spi, privateKey: req.privateKey);
|
||||||
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
||||||
|
|
||||||
final localPath = req.localPath;
|
final local = File(req.localPath);
|
||||||
final fileName = getFileName(localPath) ?? 'srvbox_sftp_upload';
|
|
||||||
final remotePath = '${req.remotePath}/$fileName';
|
|
||||||
final local = File(localPath);
|
|
||||||
if (!await local.exists()) {
|
if (!await local.exists()) {
|
||||||
mainSendPort.send(Exception('local file not exists'));
|
mainSendPort.send(Exception('local file not exists'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final localLen = await local.length();
|
||||||
|
mainSendPort.send(localLen);
|
||||||
|
mainSendPort.send(SftpWorkerStatus.loading);
|
||||||
final localFile = local.openRead().cast<Uint8List>();
|
final localFile = local.openRead().cast<Uint8List>();
|
||||||
final sftp = await client.sftp();
|
final sftp = await client.sftp();
|
||||||
final file = await sftp.open(remotePath,
|
final file = await sftp.open(
|
||||||
mode: SftpFileOpenMode.write | SftpFileOpenMode.create);
|
req.remotePath,
|
||||||
final writer = file.write(localFile);
|
mode: SftpFileOpenMode.write | SftpFileOpenMode.create,
|
||||||
|
);
|
||||||
|
final writer = file.write(localFile, onProgress: (total) {
|
||||||
|
mainSendPort.send(total / localLen * 100);
|
||||||
|
},);
|
||||||
await writer.done;
|
await writer.done;
|
||||||
await file.close();
|
await file.close();
|
||||||
mainSendPort.send(watch.elapsed);
|
mainSendPort.send(watch.elapsed);
|
||||||
|
|||||||
@@ -111,4 +111,8 @@ class SettingStore extends PersistentStore {
|
|||||||
/// Otherwise, display them on the top of server detail page
|
/// Otherwise, display them on the top of server detail page
|
||||||
StoreProperty<bool> get moveOutServerTabFuncBtns =>
|
StoreProperty<bool> get moveOutServerTabFuncBtns =>
|
||||||
property('moveOutServerTabFuncBtns', defaultValue: true);
|
property('moveOutServerTabFuncBtns', defaultValue: true);
|
||||||
|
|
||||||
|
/// Whether use `rm -rf` to delete directory on SFTP
|
||||||
|
StoreProperty<bool> get sftpRmrfDir =>
|
||||||
|
property('sftpRmrfDir', defaultValue: true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
"dockerStatusRunningAndStoppedFmt": "{runningCount} aktiv, {stoppedCount} container gestoppt.",
|
"dockerStatusRunningAndStoppedFmt": "{runningCount} aktiv, {stoppedCount} container gestoppt.",
|
||||||
"dockerStatusRunningFmt": "{count} Container aktiv",
|
"dockerStatusRunningFmt": "{count} Container aktiv",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"downloadStatus": "{percent}% von {size}",
|
|
||||||
"edit": "Bearbeiten",
|
"edit": "Bearbeiten",
|
||||||
"editVirtKeys": "Virtuelle Tasten bearbeiten",
|
"editVirtKeys": "Virtuelle Tasten bearbeiten",
|
||||||
"editor": "Editor",
|
"editor": "Editor",
|
||||||
@@ -137,6 +136,7 @@
|
|||||||
"open": "Öffnen",
|
"open": "Öffnen",
|
||||||
"paste": "Einfügen",
|
"paste": "Einfügen",
|
||||||
"path": "Pfad",
|
"path": "Pfad",
|
||||||
|
"percentOfSize": "{percent}% von {size}",
|
||||||
"pickFile": "Datei wählen",
|
"pickFile": "Datei wählen",
|
||||||
"pingAvg": "Avg:",
|
"pingAvg": "Avg:",
|
||||||
"pingInputIP": "Bitte gib eine Ziel-IP/Domain ein.",
|
"pingInputIP": "Bitte gib eine Ziel-IP/Domain ein.",
|
||||||
@@ -176,6 +176,7 @@
|
|||||||
"serverTabUnkown": "Unbekannter Status",
|
"serverTabUnkown": "Unbekannter Status",
|
||||||
"setting": "Einstellungen",
|
"setting": "Einstellungen",
|
||||||
"sftpDlPrepare": "Verbindung vorbereiten...",
|
"sftpDlPrepare": "Verbindung vorbereiten...",
|
||||||
|
"sftpRmrfDir": "Verwenden Sie `rm -rf`, um das Verzeichnis auf SFTP zu löschen",
|
||||||
"sftpSSHConnected": "SFTP Verbunden",
|
"sftpSSHConnected": "SFTP Verbunden",
|
||||||
"showDistLogo": "Distributionslogo anzeigen",
|
"showDistLogo": "Distributionslogo anzeigen",
|
||||||
"snippet": "Snippet",
|
"snippet": "Snippet",
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
"dockerStatusRunningAndStoppedFmt": "{runningCount} running, {stoppedCount} container stopped.",
|
"dockerStatusRunningAndStoppedFmt": "{runningCount} running, {stoppedCount} container stopped.",
|
||||||
"dockerStatusRunningFmt": "{count} container running.",
|
"dockerStatusRunningFmt": "{count} container running.",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"downloadStatus": "{percent}% of {size}",
|
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"editVirtKeys": "Edit virtual keys",
|
"editVirtKeys": "Edit virtual keys",
|
||||||
"editor": "Editor",
|
"editor": "Editor",
|
||||||
@@ -137,6 +136,7 @@
|
|||||||
"open": "Open",
|
"open": "Open",
|
||||||
"paste": "Paste",
|
"paste": "Paste",
|
||||||
"path": "Path",
|
"path": "Path",
|
||||||
|
"percentOfSize": "{percent}% of {size}",
|
||||||
"pickFile": "Pick file",
|
"pickFile": "Pick file",
|
||||||
"pingAvg": "Avg:",
|
"pingAvg": "Avg:",
|
||||||
"pingInputIP": "Please input a target IP / domain.",
|
"pingInputIP": "Please input a target IP / domain.",
|
||||||
@@ -176,6 +176,7 @@
|
|||||||
"serverTabUnkown": "Unknown state",
|
"serverTabUnkown": "Unknown state",
|
||||||
"setting": "Settings",
|
"setting": "Settings",
|
||||||
"sftpDlPrepare": "Preparing to connect...",
|
"sftpDlPrepare": "Preparing to connect...",
|
||||||
|
"sftpRmrfDir": "Use `rm -rf` to delete dir on SFTP",
|
||||||
"sftpSSHConnected": "SFTP Connected",
|
"sftpSSHConnected": "SFTP Connected",
|
||||||
"showDistLogo": "Show distribution logo",
|
"showDistLogo": "Show distribution logo",
|
||||||
"snippet": "Snippet",
|
"snippet": "Snippet",
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
"dockerStatusRunningAndStoppedFmt": "{runningCount} running, {stoppedCount} container stopped.",
|
"dockerStatusRunningAndStoppedFmt": "{runningCount} running, {stoppedCount} container stopped.",
|
||||||
"dockerStatusRunningFmt": "{count} wadah berjalan.",
|
"dockerStatusRunningFmt": "{count} wadah berjalan.",
|
||||||
"download": "Unduh",
|
"download": "Unduh",
|
||||||
"downloadStatus": "{percent}% dari {size}",
|
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"editVirtKeys": "Edit kunci virtual",
|
"editVirtKeys": "Edit kunci virtual",
|
||||||
"editor": "Editor",
|
"editor": "Editor",
|
||||||
@@ -137,6 +136,7 @@
|
|||||||
"open": "Membuka",
|
"open": "Membuka",
|
||||||
"paste": "Tempel",
|
"paste": "Tempel",
|
||||||
"path": "Jalur",
|
"path": "Jalur",
|
||||||
|
"percentOfSize": "{percent}% dari {size}",
|
||||||
"pickFile": "Pilih file",
|
"pickFile": "Pilih file",
|
||||||
"pingAvg": "Rata -rata:",
|
"pingAvg": "Rata -rata:",
|
||||||
"pingInputIP": "Harap masukkan IP / domain target.",
|
"pingInputIP": "Harap masukkan IP / domain target.",
|
||||||
@@ -176,6 +176,7 @@
|
|||||||
"serverTabUnkown": "Negara yang tidak diketahui",
|
"serverTabUnkown": "Negara yang tidak diketahui",
|
||||||
"setting": "Pengaturan",
|
"setting": "Pengaturan",
|
||||||
"sftpDlPrepare": "Bersiap untuk terhubung ...",
|
"sftpDlPrepare": "Bersiap untuk terhubung ...",
|
||||||
|
"sftpRmrfDir": "Gunakan `rm -rf` untuk menghapus direktori di SFTP",
|
||||||
"sftpSSHConnected": "Sftp terhubung",
|
"sftpSSHConnected": "Sftp terhubung",
|
||||||
"showDistLogo": "Tampilkan logo distribusi",
|
"showDistLogo": "Tampilkan logo distribusi",
|
||||||
"snippet": "Snippet",
|
"snippet": "Snippet",
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
"dockerStatusRunningAndStoppedFmt": "{runningCount}个正在运行, {stoppedCount}个已停止",
|
"dockerStatusRunningAndStoppedFmt": "{runningCount}个正在运行, {stoppedCount}个已停止",
|
||||||
"dockerStatusRunningFmt": "{count}个容器正在运行",
|
"dockerStatusRunningFmt": "{count}个容器正在运行",
|
||||||
"download": "下载",
|
"download": "下载",
|
||||||
"downloadStatus": "{size} 的 {percent}%",
|
|
||||||
"edit": "编辑",
|
"edit": "编辑",
|
||||||
"editVirtKeys": "编辑虚拟按键",
|
"editVirtKeys": "编辑虚拟按键",
|
||||||
"editor": "编辑器",
|
"editor": "编辑器",
|
||||||
@@ -137,6 +136,7 @@
|
|||||||
"open": "打开",
|
"open": "打开",
|
||||||
"paste": "粘贴",
|
"paste": "粘贴",
|
||||||
"path": "路径",
|
"path": "路径",
|
||||||
|
"percentOfSize": "{size} 的 {percent}%",
|
||||||
"pickFile": "选择文件",
|
"pickFile": "选择文件",
|
||||||
"pingAvg": "平均:",
|
"pingAvg": "平均:",
|
||||||
"pingInputIP": "请输入目标IP或域名",
|
"pingInputIP": "请输入目标IP或域名",
|
||||||
@@ -176,6 +176,7 @@
|
|||||||
"serverTabUnkown": "未知状态",
|
"serverTabUnkown": "未知状态",
|
||||||
"setting": "设置",
|
"setting": "设置",
|
||||||
"sftpDlPrepare": "准备连接至服务器...",
|
"sftpDlPrepare": "准备连接至服务器...",
|
||||||
|
"sftpRmrfDir": "在 SFTP 中使用 `rm -rf` 删除文件夹",
|
||||||
"sftpSSHConnected": "SFTP 已连接...",
|
"sftpSSHConnected": "SFTP 已连接...",
|
||||||
"showDistLogo": "显示发行版 Logo",
|
"showDistLogo": "显示发行版 Logo",
|
||||||
"snippet": "代码片段",
|
"snippet": "代码片段",
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
"dockerStatusRunningAndStoppedFmt": "{runningCount}個正在運行, {stoppedCount}個已停止",
|
"dockerStatusRunningAndStoppedFmt": "{runningCount}個正在運行, {stoppedCount}個已停止",
|
||||||
"dockerStatusRunningFmt": "{count}個容器正在運行",
|
"dockerStatusRunningFmt": "{count}個容器正在運行",
|
||||||
"download": "下載",
|
"download": "下載",
|
||||||
"downloadStatus": "{size} 的 {percent}%",
|
|
||||||
"edit": "編輯",
|
"edit": "編輯",
|
||||||
"editVirtKeys": "編輯虛擬按鍵",
|
"editVirtKeys": "編輯虛擬按鍵",
|
||||||
"editor": "編輯器",
|
"editor": "編輯器",
|
||||||
@@ -137,6 +136,7 @@
|
|||||||
"open": "打開",
|
"open": "打開",
|
||||||
"paste": "貼上",
|
"paste": "貼上",
|
||||||
"path": "路徑",
|
"path": "路徑",
|
||||||
|
"percentOfSize": "{size} 的 {percent}%",
|
||||||
"pickFile": "選擇文件",
|
"pickFile": "選擇文件",
|
||||||
"pingAvg": "平均:",
|
"pingAvg": "平均:",
|
||||||
"pingInputIP": "請輸入目標IP或域名",
|
"pingInputIP": "請輸入目標IP或域名",
|
||||||
@@ -176,6 +176,7 @@
|
|||||||
"serverTabUnkown": "未知狀態",
|
"serverTabUnkown": "未知狀態",
|
||||||
"setting": "設置",
|
"setting": "設置",
|
||||||
"sftpDlPrepare": "準備連接至服務器...",
|
"sftpDlPrepare": "準備連接至服務器...",
|
||||||
|
"sftpRmrfDir": "在 SFTP 中使用 `rm -rf` 刪除文件夾",
|
||||||
"sftpSSHConnected": "SFTP 已連接...",
|
"sftpSSHConnected": "SFTP 已連接...",
|
||||||
"showDistLogo": "顯示發行版 Logo",
|
"showDistLogo": "顯示發行版 Logo",
|
||||||
"snippet": "程式片段",
|
"snippet": "程式片段",
|
||||||
|
|||||||
@@ -76,7 +76,18 @@ class _EditorPageState extends State<EditorPage> with AfterLayoutMixin {
|
|||||||
body: _buildBody(),
|
body: _buildBody(),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
child: const Icon(Icons.done),
|
child: const Icon(Icons.done),
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
|
// If path is not null, then it's a file editor
|
||||||
|
// save the text and return true to pop the page
|
||||||
|
if (widget.path != null) {
|
||||||
|
showLoadingDialog(context);
|
||||||
|
await File(widget.path!).writeAsString(_controller.text);
|
||||||
|
context.pop();
|
||||||
|
context.pop(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// else it's a text editor
|
||||||
|
// return the text to the previous page
|
||||||
context.pop(_controller.text);
|
context.pop(_controller.text);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
_buildSSHVirtualKeyAutoOff(),
|
_buildSSHVirtualKeyAutoOff(),
|
||||||
_buildKeyboardType(),
|
_buildKeyboardType(),
|
||||||
_buildSSHVirtKeys(),
|
_buildSSHVirtKeys(),
|
||||||
|
_buildSftpRmrfDir(),
|
||||||
].map((e) => RoundRectCard(e)).toList(),
|
].map((e) => RoundRectCard(e)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1022,4 +1023,11 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildSftpRmrfDir() {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(_s.sftpRmrfDir),
|
||||||
|
trailing: buildSwitch(context, _setting.sftpRmrfDir),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
|
|||||||
}
|
}
|
||||||
locator<SftpProvider>().add(SftpReq(
|
locator<SftpProvider>().add(SftpReq(
|
||||||
spi,
|
spi,
|
||||||
remotePath,
|
'$remotePath/$fileName',
|
||||||
file.absolute.path,
|
file.absolute.path,
|
||||||
SftpReqType.upload,
|
SftpReqType.upload,
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
|
import 'package:after_layout/after_layout.dart';
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
@@ -25,6 +25,7 @@ import '../../../data/provider/server.dart';
|
|||||||
import '../../../data/provider/sftp.dart';
|
import '../../../data/provider/sftp.dart';
|
||||||
import '../../../data/res/path.dart';
|
import '../../../data/res/path.dart';
|
||||||
import '../../../data/res/ui.dart';
|
import '../../../data/res/ui.dart';
|
||||||
|
import '../../../data/store/setting.dart';
|
||||||
import '../../../locator.dart';
|
import '../../../locator.dart';
|
||||||
import '../../widget/custom_appbar.dart';
|
import '../../widget/custom_appbar.dart';
|
||||||
import '../../widget/fade_in.dart';
|
import '../../widget/fade_in.dart';
|
||||||
@@ -47,11 +48,12 @@ class SftpPage extends StatefulWidget {
|
|||||||
_SftpPageState createState() => _SftpPageState();
|
_SftpPageState createState() => _SftpPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SftpPageState extends State<SftpPage> {
|
class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
||||||
final SftpBrowserStatus _status = SftpBrowserStatus();
|
final SftpBrowserStatus _status = SftpBrowserStatus();
|
||||||
|
|
||||||
final _sftp = locator<SftpProvider>();
|
final _sftp = locator<SftpProvider>();
|
||||||
final _history = locator<HistoryStore>();
|
final _history = locator<HistoryStore>();
|
||||||
|
final _setting = locator<SettingStore>();
|
||||||
|
|
||||||
late S _s;
|
late S _s;
|
||||||
|
|
||||||
@@ -85,7 +87,6 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
context.pop();
|
context.pop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
|
||||||
title: TwoLineText(up: 'SFTP', down: widget.spi.name),
|
title: TwoLineText(up: 'SFTP', down: widget.spi.name),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -191,7 +192,7 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
_sftp.add(
|
_sftp.add(
|
||||||
SftpReq(
|
SftpReq(
|
||||||
widget.spi,
|
widget.spi,
|
||||||
remotePath,
|
'$remotePath/${path.split('/').last}',
|
||||||
path,
|
path,
|
||||||
SftpReqType.upload,
|
SftpReqType.upload,
|
||||||
),
|
),
|
||||||
@@ -267,9 +268,6 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
|
|
||||||
Widget _buildFileView() {
|
Widget _buildFileView() {
|
||||||
if (_status.files == null) {
|
if (_status.files == null) {
|
||||||
final p_ = widget.initPath ?? '/';
|
|
||||||
_status.path = AbsolutePath(p_);
|
|
||||||
_listDir(path: p_, client: _client);
|
|
||||||
return centerLoading;
|
return centerLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +286,7 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
itemBuilder: (_, index) => _buildItem(_status.files![index]),
|
itemBuilder: (_, index) => _buildItem(_status.files![index]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onRefresh: () => _listDir(path: _status.path?.path),
|
onRefresh: () => _listDir(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,8 +388,8 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
await completer.future;
|
await completer.future;
|
||||||
context.pop();
|
context.pop();
|
||||||
|
|
||||||
final result = await AppRoute.editor(path: localPath).go<String>(context);
|
final result = await AppRoute.editor(path: localPath).go<bool>(context);
|
||||||
if (result != null) {
|
if (result != null && result) {
|
||||||
_sftp.add(SftpReq(req.spi, remotePath, localPath, SftpReqType.upload));
|
_sftp.add(SftpReq(req.spi, remotePath, localPath, SftpReqType.upload));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,7 +429,8 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
void _delete(BuildContext context, SftpName file) {
|
void _delete(BuildContext context, SftpName file) {
|
||||||
context.pop();
|
context.pop();
|
||||||
final isDir = file.attr.isDirectory;
|
final isDir = file.attr.isDirectory;
|
||||||
final dirText = isDir ? '\n${_s.sureDirEmpty}' : '';
|
final useRmrf = _setting.sftpRmrfDir.fetch()!;
|
||||||
|
final dirText = (isDir && !useRmrf) ? '\n${_s.sureDirEmpty}' : '';
|
||||||
final text = '${_s.sureDelete(file.filename)}$dirText';
|
final text = '${_s.sureDelete(file.filename)}$dirText';
|
||||||
final child = Text(text);
|
final child = Text(text);
|
||||||
showRoundDialog(
|
showRoundDialog(
|
||||||
@@ -449,7 +448,9 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
showLoadingDialog(context);
|
showLoadingDialog(context);
|
||||||
final remotePath = _getRemotePath(file);
|
final remotePath = _getRemotePath(file);
|
||||||
try {
|
try {
|
||||||
if (file.attr.isDirectory) {
|
if (useRmrf) {
|
||||||
|
await _client!.run('rm -rf "$remotePath"');
|
||||||
|
} else if (file.attr.isDirectory) {
|
||||||
await _status.client!.rmdir(remotePath);
|
await _status.client!.rmdir(remotePath);
|
||||||
} else {
|
} else {
|
||||||
await _status.client!.remove(remotePath);
|
await _status.client!.remove(remotePath);
|
||||||
@@ -534,10 +535,6 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
label: _s.name,
|
label: _s.name,
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
|
||||||
onPressed: () => context.pop(),
|
|
||||||
child: Text(_s.cancel),
|
|
||||||
),
|
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (textController.text == '') {
|
if (textController.text == '') {
|
||||||
@@ -554,9 +551,10 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
context.pop();
|
||||||
final path = '${_status.path!.path}/${textController.text}';
|
final path = '${_status.path!.path}/${textController.text}';
|
||||||
final file = await _status.client!.open(path);
|
showLoadingDialog(context);
|
||||||
await file.writeBytes(Uint8List(0));
|
await _client!.run('touch "$path"');
|
||||||
context.pop();
|
context.pop();
|
||||||
_listDir();
|
_listDir();
|
||||||
},
|
},
|
||||||
@@ -700,6 +698,13 @@ class _SftpPageState extends State<SftpPage> {
|
|||||||
await _listDir();
|
await _listDir();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> afterFirstLayout(BuildContext context) {
|
||||||
|
final p_ = widget.initPath ?? '/';
|
||||||
|
_status.path = AbsolutePath(p_);
|
||||||
|
_listDir(path: p_, client: _client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _getDecompressCmd(String filename) {
|
String? _getDecompressCmd(String filename) {
|
||||||
|
|||||||
@@ -86,12 +86,12 @@ class _SftpMissionPageState extends State<SftpMissionPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case SftpWorkerStatus.downloading:
|
case SftpWorkerStatus.loading:
|
||||||
final percentStr = (status.progress ?? 0.0).toStringAsFixed(2);
|
final percentStr = (status.progress ?? 0.0).toStringAsFixed(2);
|
||||||
final size = (status.size ?? 0).convertBytes;
|
final size = (status.size ?? 0).convertBytes;
|
||||||
return _wrapInCard(
|
return _wrapInCard(
|
||||||
status: status,
|
status: status,
|
||||||
subtitle: _s.downloadStatus(percentStr, size),
|
subtitle: _s.percentOfSize(percentStr, size),
|
||||||
trailing: _buildDelete(status.fileName, status.id),
|
trailing: _buildDelete(status.fileName, status.id),
|
||||||
);
|
);
|
||||||
case SftpWorkerStatus.preparing:
|
case SftpWorkerStatus.preparing:
|
||||||
|
|||||||
Reference in New Issue
Block a user