add: send/receive file/folder
This commit is contained in:
parent
1db7fee6fb
commit
79217ca1d9
@ -202,7 +202,7 @@ const G = M * K;
|
|||||||
|
|
||||||
String readableFileSize(double size) {
|
String readableFileSize(double size) {
|
||||||
if (size < K) {
|
if (size < K) {
|
||||||
return size.toString() + " B";
|
return size.toStringAsFixed(2) + " B";
|
||||||
} else if (size < M) {
|
} else if (size < M) {
|
||||||
return (size / K).toStringAsFixed(2) + " KB";
|
return (size / K).toStringAsFixed(2) + " KB";
|
||||||
} else if (size < G) {
|
} else if (size < G) {
|
||||||
|
@ -393,13 +393,52 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
decoration: BoxDecoration(color: Colors.white70,border: Border.all(color: Colors.grey)),
|
decoration: BoxDecoration(color: Colors.white70,border: Border.all(color: Colors.grey)),
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => ListView.builder(
|
() => ListView.builder(
|
||||||
itemExtent: 100, itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final item = model.jobTable[index + 1];
|
final item = model.jobTable[index];
|
||||||
return Row(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text('${item.id}'),
|
Row(
|
||||||
Icon(Icons.delete)
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Transform.rotate(
|
||||||
|
angle: item.isRemote ? pi : 0,
|
||||||
|
child: Icon(Icons.send)),
|
||||||
|
SizedBox(width: 16.0,),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Tooltip(
|
||||||
|
message: item.jobName,
|
||||||
|
child: Text('${item.jobName}',
|
||||||
|
maxLines: 1,
|
||||||
|
style: TextStyle(color: Colors.black45), overflow: TextOverflow.ellipsis,)),
|
||||||
|
Wrap(
|
||||||
|
children: [
|
||||||
|
Text('${item.state.display()} ${max(0, item.fileNum)}/${item.fileCount} '),
|
||||||
|
Text('${translate("files")} ${readableFileSize(item.totalSize.toDouble())} '),
|
||||||
|
Offstage(offstage: item.state != JobState.inProgress, child: Text('${readableFileSize(item.speed) + "/s"} ')),
|
||||||
|
Text('${(item.finishedSize.toDouble() * 100 / item.totalSize.toDouble()).toStringAsFixed(2)}%'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
IconButton(icon: Icon(Icons.delete), onPressed: () {
|
||||||
|
model.jobTable.removeAt(index);
|
||||||
|
model.cancelJob(item.id);
|
||||||
|
},),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.0,),
|
||||||
|
Divider(height: 2.0, )
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -430,12 +469,15 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
Offstage(
|
Offstage(
|
||||||
offstage: isLocal,
|
offstage: isLocal,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: (){}, icon: Transform.rotate(
|
onPressed: (){
|
||||||
|
final items = getSelectedItem(isLocal);
|
||||||
|
model.sendFiles(items, isRemote: true);
|
||||||
|
}, icon: Transform.rotate(
|
||||||
angle: isLocal ? 0 : pi,
|
angle: isLocal ? 0 : pi,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.send
|
Icons.send
|
||||||
),
|
),
|
||||||
), label: Text(isLocal ? translate('Send') : translate('Receive'))),
|
), label: Text(translate('Receive'))),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -495,12 +537,15 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
Offstage(
|
Offstage(
|
||||||
offstage: !isLocal,
|
offstage: !isLocal,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: (){}, icon: Transform.rotate(
|
onPressed: (){
|
||||||
|
final items = getSelectedItem(isLocal);
|
||||||
|
model.sendFiles(items, isRemote: !isLocal);
|
||||||
|
}, icon: Transform.rotate(
|
||||||
angle: isLocal ? 0 : pi,
|
angle: isLocal ? 0 : pi,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.send
|
Icons.send
|
||||||
),
|
),
|
||||||
), label: Text(isLocal ? translate('Send') : translate('Receive'))),
|
), label: Text(translate('Send'))),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
@ -56,6 +56,10 @@ class FileModel extends ChangeNotifier {
|
|||||||
return isLocal ? _localOption.home : _remoteOption.home;
|
return isLocal ? _localOption.home : _remoteOption.home;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getJob(int id) {
|
||||||
|
return jobTable.indexWhere((element) => element.id == id);
|
||||||
|
}
|
||||||
|
|
||||||
String get currentShortPath {
|
String get currentShortPath {
|
||||||
if (currentDir.path.startsWith(currentHome)) {
|
if (currentDir.path.startsWith(currentHome)) {
|
||||||
var path = currentDir.path.replaceFirst(currentHome, "");
|
var path = currentDir.path.replaceFirst(currentHome, "");
|
||||||
@ -136,11 +140,14 @@ class FileModel extends ChangeNotifier {
|
|||||||
_jobProgress.finishedSize = int.parse(evt['finished_size']);
|
_jobProgress.finishedSize = int.parse(evt['finished_size']);
|
||||||
} else {
|
} else {
|
||||||
// Desktop uses jobTable
|
// Desktop uses jobTable
|
||||||
final job = _jobTable[id];
|
// id = index + 1
|
||||||
if (job != null) {
|
final jobIndex = getJob(id);
|
||||||
|
if (jobIndex >= 0 && _jobTable.length > jobIndex){
|
||||||
|
final job = _jobTable[jobIndex];
|
||||||
job.fileNum = int.parse(evt['file_num']);
|
job.fileNum = int.parse(evt['file_num']);
|
||||||
job.speed = double.parse(evt['speed']);
|
job.speed = double.parse(evt['speed']);
|
||||||
job.finishedSize = int.parse(evt['finished_size']);
|
job.finishedSize = int.parse(evt['finished_size']);
|
||||||
|
debugPrint("update job ${id} with ${evt}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -150,14 +157,28 @@ class FileModel extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
receiveFileDir(Map<String, dynamic> evt) {
|
receiveFileDir(Map<String, dynamic> evt) {
|
||||||
if (_remoteOption.home.isEmpty && evt['is_local'] == "false") {
|
debugPrint("recv file dir:${evt}");
|
||||||
|
if (evt['is_local'] == "false") {
|
||||||
// init remote home, the connection will automatic read remote home when established,
|
// init remote home, the connection will automatic read remote home when established,
|
||||||
try {
|
try {
|
||||||
final fd = FileDirectory.fromJson(jsonDecode(evt['value']));
|
final fd = FileDirectory.fromJson(jsonDecode(evt['value']));
|
||||||
fd.format(_remoteOption.isWindows, sort: _sortStyle);
|
fd.format(_remoteOption.isWindows, sort: _sortStyle);
|
||||||
_remoteOption.home = fd.path;
|
if (fd.id > 0){
|
||||||
debugPrint("init remote home:${fd.path}");
|
final jobIndex = getJob(fd.id);
|
||||||
_currentRemoteDir = fd;
|
if (jobIndex != -1){
|
||||||
|
final job = jobTable[jobIndex];
|
||||||
|
var totalSize = 0;
|
||||||
|
var fileCount = fd.entries.length;
|
||||||
|
fd.entries.forEach((element) {totalSize += element.size;});
|
||||||
|
job.totalSize = totalSize;
|
||||||
|
job.fileCount = fileCount;
|
||||||
|
debugPrint("update receive details:${fd.path}");
|
||||||
|
}
|
||||||
|
} else if (_remoteOption.home.isEmpty) {
|
||||||
|
_remoteOption.home = fd.path;
|
||||||
|
debugPrint("init remote home:${fd.path}");
|
||||||
|
_currentRemoteDir = fd;
|
||||||
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return;
|
return;
|
||||||
} finally {}
|
} finally {}
|
||||||
@ -166,33 +187,57 @@ class FileModel extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jobDone(Map<String, dynamic> evt) {
|
jobDone(Map<String, dynamic> evt) {
|
||||||
if (_jobResultListener.isListening) {
|
if (!isDesktop) {
|
||||||
_jobResultListener.complete(evt);
|
if (_jobResultListener.isListening) {
|
||||||
return;
|
_jobResultListener.complete(evt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_selectMode = false;
|
||||||
|
_jobProgress.state = JobState.done;
|
||||||
|
} else {
|
||||||
|
int id = int.parse(evt['id']);
|
||||||
|
final jobIndex = getJob(id);
|
||||||
|
if (jobIndex != -1) {
|
||||||
|
final job = jobTable[jobIndex];
|
||||||
|
job.finishedSize = job.totalSize;
|
||||||
|
job.state = JobState.done;
|
||||||
|
job.fileNum = int.parse(evt['file_num']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_selectMode = false;
|
|
||||||
_jobProgress.state = JobState.done;
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
jobError(Map<String, dynamic> evt) {
|
jobError(Map<String, dynamic> evt) {
|
||||||
if (_jobResultListener.isListening) {
|
if (!isDesktop) {
|
||||||
_jobResultListener.complete(evt);
|
if (_jobResultListener.isListening) {
|
||||||
return;
|
_jobResultListener.complete(evt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_selectMode = false;
|
||||||
|
_jobProgress.clear();
|
||||||
|
_jobProgress.state = JobState.error;
|
||||||
|
} else {
|
||||||
|
int jobIndex = getJob(int.parse(evt['id']));
|
||||||
|
if (jobIndex != -1) {
|
||||||
|
final job = jobTable[jobIndex];
|
||||||
|
job.state = JobState.error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint("jobError $evt");
|
debugPrint("jobError $evt");
|
||||||
_selectMode = false;
|
|
||||||
_jobProgress.clear();
|
|
||||||
_jobProgress.state = JobState.error;
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
overrideFileConfirm(Map<String, dynamic> evt) async {
|
overrideFileConfirm(Map<String, dynamic> evt) async {
|
||||||
final resp = await showFileConfirmDialog(
|
final resp = await showFileConfirmDialog(
|
||||||
translate("Overwrite"), "${evt['read_path']}", true);
|
translate("Overwrite"), "${evt['read_path']}", true);
|
||||||
|
final id = int.tryParse(evt['id']) ?? 0;
|
||||||
if (false == resp) {
|
if (false == resp) {
|
||||||
cancelJob(int.tryParse(evt['id']) ?? 0);
|
final jobIndex = getJob(id);
|
||||||
|
if (jobIndex != -1){
|
||||||
|
cancelJob(id);
|
||||||
|
final job = jobTable[jobIndex];
|
||||||
|
job.state = JobState.done;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var need_override = false;
|
var need_override = false;
|
||||||
if (resp == null) {
|
if (resp == null) {
|
||||||
@ -203,9 +248,9 @@ class FileModel extends ChangeNotifier {
|
|||||||
need_override = true;
|
need_override = true;
|
||||||
}
|
}
|
||||||
_ffi.target?.bind.sessionSetConfirmOverrideFile(id: _ffi.target?.id ?? "",
|
_ffi.target?.bind.sessionSetConfirmOverrideFile(id: _ffi.target?.id ?? "",
|
||||||
actId: evt['id'], fileNum: evt['file_num'],
|
actId: id, fileNum: int.parse(evt['file_num']),
|
||||||
needOverride: need_override, remember: fileConfirmCheckboxRemember,
|
needOverride: need_override, remember: fileConfirmCheckboxRemember,
|
||||||
isUpload: evt['is_upload']);
|
isUpload: evt['is_upload'] == "true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +364,6 @@ class FileModel extends ChangeNotifier {
|
|||||||
sendFiles(SelectedItems items, {bool isRemote = false}) {
|
sendFiles(SelectedItems items, {bool isRemote = false}) {
|
||||||
if (isDesktop) {
|
if (isDesktop) {
|
||||||
// desktop sendFiles
|
// desktop sendFiles
|
||||||
_jobProgress.state = JobState.inProgress;
|
|
||||||
final toPath =
|
final toPath =
|
||||||
isRemote ? currentRemoteDir.path : currentLocalDir.path;
|
isRemote ? currentRemoteDir.path : currentLocalDir.path;
|
||||||
final isWindows =
|
final isWindows =
|
||||||
@ -328,10 +372,14 @@ class FileModel extends ChangeNotifier {
|
|||||||
isRemote ? _localOption.showHidden : _remoteOption.showHidden ;
|
isRemote ? _localOption.showHidden : _remoteOption.showHidden ;
|
||||||
items.items.forEach((from) async {
|
items.items.forEach((from) async {
|
||||||
final jobId = ++_jobId;
|
final jobId = ++_jobId;
|
||||||
_jobTable[jobId] = JobProgress()
|
_jobTable.add(JobProgress()
|
||||||
|
..jobName = from.path
|
||||||
|
..totalSize = from.size
|
||||||
..state = JobState.inProgress
|
..state = JobState.inProgress
|
||||||
..id = jobId;
|
..id = jobId
|
||||||
await _ffi.target?.bind.sessionSendFiles(id: '${_ffi.target?.id}', actId: _jobId, path: from.path, to: PathUtil.join(toPath, from.name, isWindows)
|
..isRemote = isRemote
|
||||||
|
);
|
||||||
|
_ffi.target?.bind.sessionSendFiles(id: '${_ffi.target?.id}', actId: _jobId, path: from.path, to: PathUtil.join(toPath, from.name, isWindows)
|
||||||
,fileNum: 0, includeHidden: showHidden, isRemote: isRemote);
|
,fileNum: 0, includeHidden: showHidden, isRemote: isRemote);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -543,20 +591,20 @@ class FileModel extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendRemoveFile(String path, int fileNum, bool isLocal) {
|
sendRemoveFile(String path, int fileNum, bool isLocal) {
|
||||||
_ffi.target?.bind.sessionRemoveFile(id: '${_ffi.target?.getId()}', actId: _jobId, path: path, isRemote: !isLocal, fileNum: fileNum);
|
_ffi.target?.bind.sessionRemoveFile(id: '${_ffi.target?.id}', actId: _jobId, path: path, isRemote: !isLocal, fileNum: fileNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRemoveEmptyDir(String path, int fileNum, bool isLocal) {
|
sendRemoveEmptyDir(String path, int fileNum, bool isLocal) {
|
||||||
_ffi.target?.bind.sessionRemoveAllEmptyDirs(id: '${_ffi.target?.getId()}', actId: _jobId, path: path, isRemote: !isLocal);
|
_ffi.target?.bind.sessionRemoveAllEmptyDirs(id: '${_ffi.target?.id}', actId: _jobId, path: path, isRemote: !isLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
createDir(String path) async {
|
createDir(String path) async {
|
||||||
_jobId++;
|
_jobId++;
|
||||||
_ffi.target?.bind.sessionCreateDir(id: '${_ffi.target?.getId()}', actId: _jobId, path: path, isRemote: !isLocal);
|
_ffi.target?.bind.sessionCreateDir(id: '${_ffi.target?.id}', actId: _jobId, path: path, isRemote: !isLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelJob(int id) async {
|
cancelJob(int id) async {
|
||||||
_ffi.target?.bind.sessionCancelJob(id: '${_ffi.target?.getId()}', actId: id);
|
_ffi.target?.bind.sessionCancelJob(id: '${_ffi.target?.id}', actId: id);
|
||||||
jobReset();
|
jobReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,6 +625,21 @@ class FileModel extends ChangeNotifier {
|
|||||||
initFileFetcher() {
|
initFileFetcher() {
|
||||||
_fileFetcher.id = _ffi.target?.id;
|
_fileFetcher.id = _ffi.target?.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateFolderFiles(Map<String, dynamic> evt) {
|
||||||
|
// ret: "{\"id\":1,\"num_entries\":12,\"total_size\":1264822.0}"
|
||||||
|
Map<String,dynamic> info = json.decode(evt['info']);
|
||||||
|
int id = info['id'];
|
||||||
|
int num_entries = info['num_entries'];
|
||||||
|
double total_size = info['total_size'];
|
||||||
|
final jobIndex = getJob(id);
|
||||||
|
if (jobIndex != -1) {
|
||||||
|
final job = jobTable[jobIndex];
|
||||||
|
job.fileCount = num_entries;
|
||||||
|
job.totalSize = total_size.toInt();
|
||||||
|
}
|
||||||
|
debugPrint("update folder files: ${info}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class JobResultListener<T> {
|
class JobResultListener<T> {
|
||||||
@ -784,12 +847,33 @@ class Entry {
|
|||||||
|
|
||||||
enum JobState { none, inProgress, done, error }
|
enum JobState { none, inProgress, done, error }
|
||||||
|
|
||||||
|
extension JobStateDisplay on JobState {
|
||||||
|
String display() {
|
||||||
|
switch (this) {
|
||||||
|
case JobState.none:
|
||||||
|
return translate("Waiting");
|
||||||
|
case JobState.inProgress:
|
||||||
|
return translate("Transfer File");
|
||||||
|
case JobState.done:
|
||||||
|
return translate("Finished");
|
||||||
|
case JobState.error:
|
||||||
|
return translate("Error");
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class JobProgress {
|
class JobProgress {
|
||||||
JobState state = JobState.none;
|
JobState state = JobState.none;
|
||||||
var id = 0;
|
var id = 0;
|
||||||
var fileNum = 0;
|
var fileNum = 0;
|
||||||
var speed = 0.0;
|
var speed = 0.0;
|
||||||
var finishedSize = 0;
|
var finishedSize = 0;
|
||||||
|
var totalSize = 0;
|
||||||
|
var fileCount = 0;
|
||||||
|
var isRemote = false;
|
||||||
|
var jobName = "";
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
state = JobState.none;
|
state = JobState.none;
|
||||||
@ -797,6 +881,8 @@ class JobProgress {
|
|||||||
fileNum = 0;
|
fileNum = 0;
|
||||||
speed = 0;
|
speed = 0;
|
||||||
finishedSize = 0;
|
finishedSize = 0;
|
||||||
|
jobName = "";
|
||||||
|
fileCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +168,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
parent.target?.fileModel.jobError(evt);
|
parent.target?.fileModel.jobError(evt);
|
||||||
} else if (name == 'override_file_confirm') {
|
} else if (name == 'override_file_confirm') {
|
||||||
parent.target?.fileModel.overrideFileConfirm(evt);
|
parent.target?.fileModel.overrideFileConfirm(evt);
|
||||||
|
} else if (name == 'update_folder_files') {
|
||||||
|
parent.target?.fileModel.updateFolderFiles(evt);
|
||||||
} else if (name == 'try_start_without_auth') {
|
} else if (name == 'try_start_without_auth') {
|
||||||
parent.target?.serverModel.loginRequest(evt);
|
parent.target?.serverModel.loginRequest(evt);
|
||||||
} else if (name == 'on_client_authorized') {
|
} else if (name == 'on_client_authorized') {
|
||||||
@ -217,6 +219,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
parent.target?.fileModel.jobError(evt);
|
parent.target?.fileModel.jobError(evt);
|
||||||
} else if (name == 'override_file_confirm') {
|
} else if (name == 'override_file_confirm') {
|
||||||
parent.target?.fileModel.overrideFileConfirm(evt);
|
parent.target?.fileModel.overrideFileConfirm(evt);
|
||||||
|
} else if (name == 'update_folder_files') {
|
||||||
|
parent.target?.fileModel.updateFolderFiles(evt);
|
||||||
} else if (name == 'try_start_without_auth') {
|
} else if (name == 'try_start_without_auth') {
|
||||||
parent.target?.serverModel.loginRequest(evt);
|
parent.target?.serverModel.loginRequest(evt);
|
||||||
} else if (name == 'on_client_authorized') {
|
} else if (name == 'on_client_authorized') {
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
pub use arboard::Clipboard as ClipboardContext;
|
pub use arboard::Clipboard as ClipboardContext;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
allow_err,
|
allow_err,
|
||||||
anyhow::bail,
|
anyhow::bail,
|
||||||
@ -14,7 +18,6 @@ use hbb_common::{
|
|||||||
};
|
};
|
||||||
// #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))]
|
// #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))]
|
||||||
use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all};
|
use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all};
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
pub const CLIPBOARD_NAME: &'static str = "clipboard";
|
pub const CLIPBOARD_NAME: &'static str = "clipboard";
|
||||||
pub const CLIPBOARD_INTERVAL: u64 = 333;
|
pub const CLIPBOARD_INTERVAL: u64 = 333;
|
||||||
@ -633,3 +636,30 @@ pub fn make_fd_to_json(fd: FileDirectory) -> String {
|
|||||||
fd_json.insert("entries".into(), json!(entries));
|
fd_json.insert("entries".into(), json!(entries));
|
||||||
serde_json::to_string(&fd_json).unwrap_or("".into())
|
serde_json::to_string(&fd_json).unwrap_or("".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_fd_flutter(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> String {
|
||||||
|
let mut m = serde_json::Map::new();
|
||||||
|
m.insert("id".into(), json!(id));
|
||||||
|
let mut a = vec![];
|
||||||
|
let mut n: u64 = 0;
|
||||||
|
for entry in entries {
|
||||||
|
n += entry.size;
|
||||||
|
if only_count {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut e = serde_json::Map::new();
|
||||||
|
e.insert("name".into(), json!(entry.name.to_owned()));
|
||||||
|
let tmp = entry.entry_type.value();
|
||||||
|
e.insert("type".into(), json!(if tmp == 0 { 1 } else { tmp }));
|
||||||
|
e.insert("time".into(), json!(entry.modified_time as f64));
|
||||||
|
e.insert("size".into(), json!(entry.size as f64));
|
||||||
|
a.push(e);
|
||||||
|
}
|
||||||
|
if only_count {
|
||||||
|
m.insert("num_entries".into(), json!(entries.len() as i32));
|
||||||
|
} else {
|
||||||
|
m.insert("entries".into(), json!(a));
|
||||||
|
}
|
||||||
|
m.insert("total_size".into(), json!(n as f64));
|
||||||
|
serde_json::to_string(&m).unwrap_or("".into())
|
||||||
|
}
|
||||||
|
@ -27,7 +27,7 @@ use hbb_common::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::common::make_fd_to_json;
|
use crate::common::make_fd_to_json;
|
||||||
use crate::{client::*, flutter_ffi::EventToUI};
|
use crate::{client::*, flutter_ffi::EventToUI, make_fd_flutter};
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
// static ref SESSION: Arc<RwLock<Option<Session>>> = Default::default();
|
// static ref SESSION: Arc<RwLock<Option<Session>>> = Default::default();
|
||||||
@ -991,6 +991,9 @@ impl Connection {
|
|||||||
to,
|
to,
|
||||||
job.files().len()
|
job.files().len()
|
||||||
);
|
);
|
||||||
|
let m = make_fd_flutter(id, job.files(), true);
|
||||||
|
self.session
|
||||||
|
.push_event("update_folder_files", vec![("info", &m)]);
|
||||||
let files = job.files().clone();
|
let files = job.files().clone();
|
||||||
self.read_jobs.push(job);
|
self.read_jobs.push(job);
|
||||||
self.timer = time::interval(MILLI1);
|
self.timer = time::interval(MILLI1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user