parent
579e0fac36
commit
ed18e3c786
@ -262,6 +262,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
Offstage(
|
Offstage(
|
||||||
offstage: item.state != JobState.paused,
|
offstage: item.state != JobState.paused,
|
||||||
child: MenuButton(
|
child: MenuButton(
|
||||||
|
tooltip: translate("Resume"),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
jobController.resumeJob(item.id);
|
jobController.resumeJob(item.id);
|
||||||
},
|
},
|
||||||
@ -274,6 +275,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
MenuButton(
|
MenuButton(
|
||||||
|
tooltip: translate("Delete"),
|
||||||
padding: EdgeInsets.only(right: 15),
|
padding: EdgeInsets.only(right: 15),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
"assets/close.svg",
|
"assets/close.svg",
|
||||||
@ -521,6 +523,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
MenuButton(
|
MenuButton(
|
||||||
|
tooltip: translate('Back'),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
right: 3,
|
right: 3,
|
||||||
),
|
),
|
||||||
@ -540,6 +543,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
MenuButton(
|
MenuButton(
|
||||||
|
tooltip: translate('Parent directory'),
|
||||||
child: RotatedBox(
|
child: RotatedBox(
|
||||||
quarterTurns: 3,
|
quarterTurns: 3,
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
@ -604,6 +608,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
switch (_locationStatus.value) {
|
switch (_locationStatus.value) {
|
||||||
case LocationStatus.bread:
|
case LocationStatus.bread:
|
||||||
return MenuButton(
|
return MenuButton(
|
||||||
|
tooltip: translate('Search'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_locationStatus.value = LocationStatus.fileSearchBar;
|
_locationStatus.value = LocationStatus.fileSearchBar;
|
||||||
Future.delayed(
|
Future.delayed(
|
||||||
@ -630,6 +635,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
);
|
);
|
||||||
case LocationStatus.fileSearchBar:
|
case LocationStatus.fileSearchBar:
|
||||||
return MenuButton(
|
return MenuButton(
|
||||||
|
tooltip: translate('Clear'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
onSearchText("", isLocal);
|
onSearchText("", isLocal);
|
||||||
_locationStatus.value = LocationStatus.bread;
|
_locationStatus.value = LocationStatus.bread;
|
||||||
@ -645,6 +651,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
MenuButton(
|
MenuButton(
|
||||||
|
tooltip: translate('Refresh File'),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
left: 3,
|
left: 3,
|
||||||
),
|
),
|
||||||
@ -670,6 +677,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
isLocal ? MainAxisAlignment.start : MainAxisAlignment.end,
|
isLocal ? MainAxisAlignment.start : MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
MenuButton(
|
MenuButton(
|
||||||
|
tooltip: translate('Home'),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
right: 3,
|
right: 3,
|
||||||
),
|
),
|
||||||
@ -685,11 +693,27 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
hoverColor: Theme.of(context).hoverColor,
|
hoverColor: Theme.of(context).hoverColor,
|
||||||
),
|
),
|
||||||
MenuButton(
|
MenuButton(
|
||||||
|
tooltip: translate('Create Folder'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final name = TextEditingController();
|
final name = TextEditingController();
|
||||||
|
String? errorText;
|
||||||
_ffi.dialogManager.show((setState, close, context) {
|
_ffi.dialogManager.show((setState, close, context) {
|
||||||
|
name.addListener(() {
|
||||||
|
if (errorText != null) {
|
||||||
|
setState(() {
|
||||||
|
errorText = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
submit() {
|
submit() {
|
||||||
if (name.value.text.isNotEmpty) {
|
if (name.value.text.isNotEmpty) {
|
||||||
|
if (!PathUtil.validName(name.value.text,
|
||||||
|
controller.options.value.isWindows)) {
|
||||||
|
setState(() {
|
||||||
|
errorText = translate("Invalid folder name");
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
controller.createDir(PathUtil.join(
|
controller.createDir(PathUtil.join(
|
||||||
controller.directory.value.path,
|
controller.directory.value.path,
|
||||||
name.value.text,
|
name.value.text,
|
||||||
@ -721,6 +745,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
labelText: translate(
|
labelText: translate(
|
||||||
"Please enter the folder name",
|
"Please enter the folder name",
|
||||||
),
|
),
|
||||||
|
errorText: errorText,
|
||||||
),
|
),
|
||||||
controller: name,
|
controller: name,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
@ -754,6 +779,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
hoverColor: Theme.of(context).hoverColor,
|
hoverColor: Theme.of(context).hoverColor,
|
||||||
),
|
),
|
||||||
Obx(() => MenuButton(
|
Obx(() => MenuButton(
|
||||||
|
tooltip: translate('Delete'),
|
||||||
onPressed: SelectedItems.valid(selectedItems.items)
|
onPressed: SelectedItems.valid(selectedItems.items)
|
||||||
? () async {
|
? () async {
|
||||||
await (controller
|
await (controller
|
||||||
@ -885,6 +911,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
menuPos = RelativeRect.fromLTRB(x, y, x, y);
|
menuPos = RelativeRect.fromLTRB(x, y, x, y);
|
||||||
},
|
},
|
||||||
child: MenuButton(
|
child: MenuButton(
|
||||||
|
tooltip: translate('More'),
|
||||||
onPressed: () => mod_menu.showMenu(
|
onPressed: () => mod_menu.showMenu(
|
||||||
context: context,
|
context: context,
|
||||||
position: menuPos,
|
position: menuPos,
|
||||||
@ -974,6 +1001,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
final lastModifiedStr = entry.isDrive
|
final lastModifiedStr = entry.isDrive
|
||||||
? " "
|
? " "
|
||||||
: "${entry.lastModified().toString().replaceAll(".000", "")} ";
|
: "${entry.lastModified().toString().replaceAll(".000", "")} ";
|
||||||
|
var secondaryPosition = RelativeRect.fromLTRB(0, 0, 0, 0);
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 1),
|
padding: EdgeInsets.symmetric(vertical: 1),
|
||||||
child: Obx(() => Container(
|
child: Obx(() => Container(
|
||||||
@ -1038,6 +1066,35 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
_onSelectedChanged(
|
_onSelectedChanged(
|
||||||
items, filteredEntries, entry, isLocal);
|
items, filteredEntries, entry, isLocal);
|
||||||
},
|
},
|
||||||
|
onSecondaryTap: () {
|
||||||
|
final items = [
|
||||||
|
if (!entry.isDrive &&
|
||||||
|
versionCmp(_ffi.ffiModel.pi.version,
|
||||||
|
"1.3.0") >=
|
||||||
|
0)
|
||||||
|
mod_menu.PopupMenuItem(
|
||||||
|
child: Text("Rename"),
|
||||||
|
height: CustomPopupMenuTheme.height,
|
||||||
|
onTap: () {
|
||||||
|
controller.renameAction(entry, isLocal);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
];
|
||||||
|
if (items.isNotEmpty) {
|
||||||
|
mod_menu.showMenu(
|
||||||
|
context: context,
|
||||||
|
position: secondaryPosition,
|
||||||
|
items: items,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSecondaryTapDown: (details) {
|
||||||
|
secondaryPosition = RelativeRect.fromLTRB(
|
||||||
|
details.globalPosition.dx,
|
||||||
|
details.globalPosition.dy,
|
||||||
|
details.globalPosition.dx,
|
||||||
|
details.globalPosition.dy);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 2.0,
|
width: 2.0,
|
||||||
|
@ -1157,6 +1157,16 @@ class __FileTransferLogPageState extends State<_FileTransferLogPage> {
|
|||||||
Text(translate('Create Folder'))
|
Text(translate('Create Folder'))
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
case CmFileAction.rename:
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.drive_file_move_outlined,
|
||||||
|
color: Theme.of(context).tabBarTheme.labelColor,
|
||||||
|
),
|
||||||
|
Text(translate('Rename'))
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ class _MenuButtonState extends State<MenuButton> {
|
|||||||
return Padding(
|
return Padding(
|
||||||
padding: widget.padding,
|
padding: widget.padding,
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
|
waitDuration: Duration(milliseconds: 300),
|
||||||
message: widget.tooltip,
|
message: widget.tooltip,
|
||||||
child: Material(
|
child: Material(
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
|
@ -204,36 +204,54 @@ class _FileManagerPageState extends State<FileManagerPage> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
} else if (v == "folder") {
|
} else if (v == "folder") {
|
||||||
final name = TextEditingController();
|
final name = TextEditingController();
|
||||||
gFFI.dialogManager
|
String? errorText;
|
||||||
.show((setState, close, context) => CustomAlertDialog(
|
gFFI.dialogManager.show((setState, close, context) {
|
||||||
title: Text(translate("Create Folder")),
|
name.addListener(() {
|
||||||
content: Column(
|
if (errorText != null) {
|
||||||
mainAxisSize: MainAxisSize.min,
|
setState(() {
|
||||||
children: [
|
errorText = null;
|
||||||
TextFormField(
|
});
|
||||||
decoration: InputDecoration(
|
}
|
||||||
labelText: translate(
|
});
|
||||||
"Please enter the folder name"),
|
return CustomAlertDialog(
|
||||||
),
|
title: Text(translate("Create Folder")),
|
||||||
controller: name,
|
content: Column(
|
||||||
),
|
mainAxisSize: MainAxisSize.min,
|
||||||
],
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText:
|
||||||
|
translate("Please enter the folder name"),
|
||||||
|
errorText: errorText,
|
||||||
),
|
),
|
||||||
actions: [
|
controller: name,
|
||||||
dialogButton("Cancel",
|
),
|
||||||
onPressed: () => close(false),
|
],
|
||||||
isOutline: true),
|
),
|
||||||
dialogButton("OK", onPressed: () {
|
actions: [
|
||||||
if (name.value.text.isNotEmpty) {
|
dialogButton("Cancel",
|
||||||
currentFileController.createDir(
|
onPressed: () => close(false), isOutline: true),
|
||||||
PathUtil.join(
|
dialogButton("OK", onPressed: () {
|
||||||
currentDir.path,
|
if (name.value.text.isNotEmpty) {
|
||||||
name.value.text,
|
if (!PathUtil.validName(
|
||||||
currentOptions.isWindows));
|
name.value.text,
|
||||||
close();
|
currentFileController
|
||||||
}
|
.options.value.isWindows)) {
|
||||||
})
|
setState(() {
|
||||||
]));
|
errorText =
|
||||||
|
translate("Invalid folder name");
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentFileController.createDir(PathUtil.join(
|
||||||
|
currentDir.path,
|
||||||
|
name.value.text,
|
||||||
|
currentOptions.isWindows));
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
});
|
||||||
} else if (v == "hidden") {
|
} else if (v == "hidden") {
|
||||||
currentFileController.toggleShowHidden();
|
currentFileController.toggleShowHidden();
|
||||||
}
|
}
|
||||||
@ -497,7 +515,15 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
child: Text(translate("Properties")),
|
child: Text(translate("Properties")),
|
||||||
value: "properties",
|
value: "properties",
|
||||||
enabled: false,
|
enabled: false,
|
||||||
)
|
),
|
||||||
|
if (!entries[index].isDrive &&
|
||||||
|
versionCmp(gFFI.ffiModel.pi.version,
|
||||||
|
"1.3.0") >=
|
||||||
|
0)
|
||||||
|
PopupMenuItem(
|
||||||
|
child: Text(translate("Rename")),
|
||||||
|
value: "rename",
|
||||||
|
)
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
onSelected: (v) {
|
onSelected: (v) {
|
||||||
@ -509,6 +535,9 @@ class _FileManagerViewState extends State<FileManagerView> {
|
|||||||
_selectedItems.clear();
|
_selectedItems.clear();
|
||||||
widget.selectMode.toggle(isLocal);
|
widget.selectMode.toggle(isLocal);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
} else if (v == "rename") {
|
||||||
|
controller.renameAction(
|
||||||
|
entries[index], isLocal);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
@ -291,7 +291,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(translate('Enable trusted devices')),
|
Text(translate('Enable trusted devices')),
|
||||||
Text(translate('enable-trusted-devices-tip'),
|
Text('* ${translate('enable-trusted-devices-tip')}',
|
||||||
style: Theme.of(context).textTheme.bodySmall),
|
style: Theme.of(context).textTheme.bodySmall),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -33,6 +33,8 @@ class CmFileModel {
|
|||||||
_onFileRemove(evt['remove']);
|
_onFileRemove(evt['remove']);
|
||||||
} else if (evt['create_dir'] != null) {
|
} else if (evt['create_dir'] != null) {
|
||||||
_onDirCreate(evt['create_dir']);
|
_onDirCreate(evt['create_dir']);
|
||||||
|
} else if (evt['rename'] != null) {
|
||||||
|
_onRename(evt['rename']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +61,6 @@ class CmFileModel {
|
|||||||
|
|
||||||
_dealOneJob(dynamic l, bool calcSpeed) {
|
_dealOneJob(dynamic l, bool calcSpeed) {
|
||||||
final data = TransferJobSerdeData.fromJson(l);
|
final data = TransferJobSerdeData.fromJson(l);
|
||||||
Client? client =
|
|
||||||
gFFI.serverModel.clients.firstWhereOrNull((e) => e.id == data.connId);
|
|
||||||
var jobTable = _jobTables[data.connId];
|
var jobTable = _jobTables[data.connId];
|
||||||
if (jobTable == null) {
|
if (jobTable == null) {
|
||||||
debugPrint("jobTable should not be null");
|
debugPrint("jobTable should not be null");
|
||||||
@ -70,12 +70,7 @@ class CmFileModel {
|
|||||||
if (job == null) {
|
if (job == null) {
|
||||||
job = CmFileLog();
|
job = CmFileLog();
|
||||||
jobTable.add(job);
|
jobTable.add(job);
|
||||||
final currentSelectedTab =
|
_addUnread(data.connId);
|
||||||
gFFI.serverModel.tabController.state.value.selectedTabInfo;
|
|
||||||
if (!(gFFI.chatModel.isShowCMSidePage &&
|
|
||||||
currentSelectedTab.key == data.connId.toString())) {
|
|
||||||
client?.unreadChatMessageCount.value += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
job.id = data.id;
|
job.id = data.id;
|
||||||
job.action =
|
job.action =
|
||||||
@ -167,8 +162,6 @@ class CmFileModel {
|
|||||||
try {
|
try {
|
||||||
dynamic d = jsonDecode(log);
|
dynamic d = jsonDecode(log);
|
||||||
FileActionLog data = FileActionLog.fromJson(d);
|
FileActionLog data = FileActionLog.fromJson(d);
|
||||||
Client? client =
|
|
||||||
gFFI.serverModel.clients.firstWhereOrNull((e) => e.id == data.connId);
|
|
||||||
var jobTable = _jobTables[data.connId];
|
var jobTable = _jobTables[data.connId];
|
||||||
if (jobTable == null) {
|
if (jobTable == null) {
|
||||||
debugPrint("jobTable should not be null");
|
debugPrint("jobTable should not be null");
|
||||||
@ -179,17 +172,45 @@ class CmFileModel {
|
|||||||
..fileName = data.path
|
..fileName = data.path
|
||||||
..action = CmFileAction.createDir
|
..action = CmFileAction.createDir
|
||||||
..state = JobState.done);
|
..state = JobState.done);
|
||||||
final currentSelectedTab =
|
_addUnread(data.connId);
|
||||||
gFFI.serverModel.tabController.state.value.selectedTabInfo;
|
|
||||||
if (!(gFFI.chatModel.isShowCMSidePage &&
|
|
||||||
currentSelectedTab.key == data.connId.toString())) {
|
|
||||||
client?.unreadChatMessageCount.value += 1;
|
|
||||||
}
|
|
||||||
jobTable.refresh();
|
jobTable.refresh();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('$e');
|
debugPrint('$e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onRename(dynamic log) {
|
||||||
|
try {
|
||||||
|
dynamic d = jsonDecode(log);
|
||||||
|
FileRenamenLog data = FileRenamenLog.fromJson(d);
|
||||||
|
var jobTable = _jobTables[data.connId];
|
||||||
|
if (jobTable == null) {
|
||||||
|
debugPrint("jobTable should not be null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final fileName = '${data.path} -> ${data.newName}';
|
||||||
|
jobTable.add(CmFileLog()
|
||||||
|
..id = 0
|
||||||
|
..fileName = fileName
|
||||||
|
..action = CmFileAction.rename
|
||||||
|
..state = JobState.done);
|
||||||
|
_addUnread(data.connId);
|
||||||
|
jobTable.refresh();
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('$e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_addUnread(int connId) {
|
||||||
|
Client? client =
|
||||||
|
gFFI.serverModel.clients.firstWhereOrNull((e) => e.id == connId);
|
||||||
|
final currentSelectedTab =
|
||||||
|
gFFI.serverModel.tabController.state.value.selectedTabInfo;
|
||||||
|
if (!(gFFI.chatModel.isShowCMSidePage &&
|
||||||
|
currentSelectedTab.key == connId.toString())) {
|
||||||
|
client?.unreadChatMessageCount.value += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CmFileAction {
|
enum CmFileAction {
|
||||||
@ -198,6 +219,7 @@ enum CmFileAction {
|
|||||||
localToRemote,
|
localToRemote,
|
||||||
remove,
|
remove,
|
||||||
createDir,
|
createDir,
|
||||||
|
rename,
|
||||||
}
|
}
|
||||||
|
|
||||||
class CmFileLog {
|
class CmFileLog {
|
||||||
@ -285,3 +307,22 @@ class FileActionLog {
|
|||||||
dir: d['dir'] ?? false,
|
dir: d['dir'] ?? false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FileRenamenLog {
|
||||||
|
int connId = 0;
|
||||||
|
String path = '';
|
||||||
|
String newName = '';
|
||||||
|
|
||||||
|
FileRenamenLog({
|
||||||
|
required this.connId,
|
||||||
|
required this.path,
|
||||||
|
required this.newName,
|
||||||
|
});
|
||||||
|
|
||||||
|
FileRenamenLog.fromJson(dynamic d)
|
||||||
|
: this(
|
||||||
|
connId: d['connId'] ?? 0,
|
||||||
|
path: d['path'] ?? '',
|
||||||
|
newName: d['newName'] ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
|
import 'package:flutter_hbb/common/widgets/dialog.dart';
|
||||||
import 'package:flutter_hbb/utils/event_loop.dart';
|
import 'package:flutter_hbb/utils/event_loop.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
@ -642,6 +643,77 @@ class FileController {
|
|||||||
path: path,
|
path: path,
|
||||||
isRemote: !isLocal);
|
isRemote: !isLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> renameAction(Entry item, bool isLocal) async {
|
||||||
|
final textEditingController = TextEditingController(text: item.name);
|
||||||
|
String? errorText;
|
||||||
|
dialogManager?.show((setState, close, context) {
|
||||||
|
textEditingController.addListener(() {
|
||||||
|
if (errorText != null) {
|
||||||
|
setState(() {
|
||||||
|
errorText = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
submit() async {
|
||||||
|
final newName = textEditingController.text;
|
||||||
|
if (newName.isEmpty || newName == item.name) {
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (directory.value.entries.any((e) => e.name == newName)) {
|
||||||
|
setState(() {
|
||||||
|
errorText = translate("Already exists");
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!PathUtil.validName(newName, options.value.isWindows)) {
|
||||||
|
setState(() {
|
||||||
|
if (item.isDirectory) {
|
||||||
|
errorText = translate("Invalid folder name");
|
||||||
|
} else {
|
||||||
|
errorText = translate("Invalid file name");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await bind.sessionRenameFile(
|
||||||
|
sessionId: sessionId,
|
||||||
|
actId: JobController.jobID.next(),
|
||||||
|
path: item.path,
|
||||||
|
newName: newName,
|
||||||
|
isRemote: !isLocal);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return CustomAlertDialog(
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
DialogTextField(
|
||||||
|
title: '${translate('Rename')} ${item.name}',
|
||||||
|
controller: textEditingController,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
dialogButton(
|
||||||
|
"Cancel",
|
||||||
|
icon: Icon(Icons.close_rounded),
|
||||||
|
onPressed: close,
|
||||||
|
isOutline: true,
|
||||||
|
),
|
||||||
|
dialogButton(
|
||||||
|
"OK",
|
||||||
|
icon: Icon(Icons.done_rounded),
|
||||||
|
onPressed: submit,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onSubmit: submit,
|
||||||
|
onCancel: close,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class JobController {
|
class JobController {
|
||||||
@ -1083,6 +1155,13 @@ class PathUtil {
|
|||||||
final pathUtil = isWindows ? windowsContext : posixContext;
|
final pathUtil = isWindows ? windowsContext : posixContext;
|
||||||
return pathUtil.dirname(path);
|
return pathUtil.dirname(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool validName(String name, bool isWindows) {
|
||||||
|
final unixFileNamePattern = RegExp(r'^[^/\0]+$');
|
||||||
|
final windowsFileNamePattern = RegExp(r'^[^<>:"/\\|?*]+$');
|
||||||
|
final reg = isWindows ? windowsFileNamePattern : unixFileNamePattern;
|
||||||
|
return reg.hasMatch(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DirectoryOptions {
|
class DirectoryOptions {
|
||||||
|
@ -371,6 +371,12 @@ message ReadAllFiles {
|
|||||||
bool include_hidden = 3;
|
bool include_hidden = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message FileRename {
|
||||||
|
int32 id = 1;
|
||||||
|
string path = 2;
|
||||||
|
string new_name = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message FileAction {
|
message FileAction {
|
||||||
oneof union {
|
oneof union {
|
||||||
ReadDir read_dir = 1;
|
ReadDir read_dir = 1;
|
||||||
@ -382,6 +388,7 @@ message FileAction {
|
|||||||
ReadAllFiles all_files = 7;
|
ReadAllFiles all_files = 7;
|
||||||
FileTransferCancel cancel = 8;
|
FileTransferCancel cancel = 8;
|
||||||
FileTransferSendConfirmRequest send_confirm = 9;
|
FileTransferSendConfirmRequest send_confirm = 9;
|
||||||
|
FileRename rename = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,6 +838,21 @@ pub fn create_dir(dir: &str) -> ResultType<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn rename_file(path: &str, new_name: &str) -> ResultType<()> {
|
||||||
|
let path = std::path::Path::new(&path);
|
||||||
|
if path.exists() {
|
||||||
|
let dir = path
|
||||||
|
.parent()
|
||||||
|
.ok_or(anyhow!("Parent directoy of {path:?} not exists"))?;
|
||||||
|
let new_path = dir.join(&new_name);
|
||||||
|
std::fs::rename(&path, &new_path)?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("{path:?} not exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_windows_path(entries: &mut Vec<FileEntry>) {
|
pub fn transform_windows_path(entries: &mut Vec<FileEntry>) {
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
|
@ -3180,6 +3180,7 @@ pub enum Data {
|
|||||||
NewVoiceCall,
|
NewVoiceCall,
|
||||||
CloseVoiceCall,
|
CloseVoiceCall,
|
||||||
ResetDecoder(Option<usize>),
|
ResetDecoder(Option<usize>),
|
||||||
|
RenameFile((i32, String, String, bool)),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Keycode for key events.
|
/// Keycode for key events.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use hbb_common::{fs, message_proto::*, log};
|
use hbb_common::{fs, log, message_proto::*};
|
||||||
|
|
||||||
use super::{Data, Interface};
|
use super::{Data, Interface};
|
||||||
|
|
||||||
@ -7,7 +7,12 @@ pub trait FileManager: Interface {
|
|||||||
fs::get_home_as_string()
|
fs::get_home_as_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli", feature = "flutter")))]
|
#[cfg(not(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_os = "ios",
|
||||||
|
feature = "cli",
|
||||||
|
feature = "flutter"
|
||||||
|
)))]
|
||||||
fn read_dir(&self, path: String, include_hidden: bool) -> sciter::Value {
|
fn read_dir(&self, path: String, include_hidden: bool) -> sciter::Value {
|
||||||
match fs::read_dir(&fs::get_path(&path), include_hidden) {
|
match fs::read_dir(&fs::get_path(&path), include_hidden) {
|
||||||
Err(_) => sciter::Value::null(),
|
Err(_) => sciter::Value::null(),
|
||||||
@ -20,7 +25,12 @@ pub trait FileManager: Interface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "ios", feature = "cli", feature = "flutter"))]
|
#[cfg(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_os = "ios",
|
||||||
|
feature = "cli",
|
||||||
|
feature = "flutter"
|
||||||
|
))]
|
||||||
fn read_dir(&self, path: &str, include_hidden: bool) -> String {
|
fn read_dir(&self, path: &str, include_hidden: bool) -> String {
|
||||||
use crate::common::make_fd_to_json;
|
use crate::common::make_fd_to_json;
|
||||||
match fs::read_dir(&fs::get_path(path), include_hidden) {
|
match fs::read_dir(&fs::get_path(path), include_hidden) {
|
||||||
@ -136,4 +146,8 @@ pub trait FileManager: Interface {
|
|||||||
is_upload,
|
is_upload,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rename_file(&self, act_id: i32, path: String, new_name: String, is_remote: bool) {
|
||||||
|
self.send(Data::RenameFile((act_id, path, new_name, is_remote)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -817,6 +817,25 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Data::RenameFile((id, path, new_name, is_remote)) => {
|
||||||
|
if is_remote {
|
||||||
|
let mut msg_out = Message::new();
|
||||||
|
let mut file_action = FileAction::new();
|
||||||
|
file_action.set_rename(FileRename {
|
||||||
|
id,
|
||||||
|
path,
|
||||||
|
new_name,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
msg_out.set_file_action(file_action);
|
||||||
|
allow_err!(peer.send(&msg_out).await);
|
||||||
|
} else {
|
||||||
|
let err = fs::rename_file(&path, &new_name)
|
||||||
|
.err()
|
||||||
|
.map(|e| e.to_string());
|
||||||
|
self.handle_job_status(id, -1, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
Data::RecordScreen(start, display, w, h, id) => {
|
Data::RecordScreen(start, display, w, h, id) => {
|
||||||
let _ = self
|
let _ = self
|
||||||
.video_sender
|
.video_sender
|
||||||
|
@ -710,6 +710,18 @@ pub fn session_resume_job(session_id: SessionID, act_id: i32, is_remote: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn session_rename_file(
|
||||||
|
session_id: SessionID,
|
||||||
|
act_id: i32,
|
||||||
|
path: String,
|
||||||
|
new_name: String,
|
||||||
|
is_remote: bool,
|
||||||
|
) {
|
||||||
|
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||||
|
session.rename_file(act_id, path, new_name, is_remote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn session_elevate_direct(session_id: SessionID) {
|
pub fn session_elevate_direct(session_id: SessionID) {
|
||||||
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||||
session.elevate_direct();
|
session.elevate_direct();
|
||||||
|
@ -102,6 +102,11 @@ pub enum FS {
|
|||||||
last_modified: u64,
|
last_modified: u64,
|
||||||
is_upload: bool,
|
is_upload: bool,
|
||||||
},
|
},
|
||||||
|
Rename {
|
||||||
|
id: i32,
|
||||||
|
path: String,
|
||||||
|
new_name: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", "平台"),
|
("Platform", "平台"),
|
||||||
("Days remaining", "剩余天数"),
|
("Days remaining", "剩余天数"),
|
||||||
("enable-trusted-devices-tip", "允许受信任的设备跳过 2FA 验证"),
|
("enable-trusted-devices-tip", "允许受信任的设备跳过 2FA 验证"),
|
||||||
|
("Parent directory", "父目录"),
|
||||||
|
("Resume", "继续"),
|
||||||
|
("Invalid file name", "无效文件名"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", "Platforma"),
|
("Platform", "Platforma"),
|
||||||
("Days remaining", "Zbývajících dnů"),
|
("Days remaining", "Zbývajících dnů"),
|
||||||
("enable-trusted-devices-tip", "Přeskočte 2FA ověření na důvěryhodných zařízeních"),
|
("enable-trusted-devices-tip", "Přeskočte 2FA ověření na důvěryhodných zařízeních"),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", "Plattform"),
|
("Platform", "Plattform"),
|
||||||
("Days remaining", "Verbleibende Tage"),
|
("Days remaining", "Verbleibende Tage"),
|
||||||
("enable-trusted-devices-tip", "2FA-Verifizierung auf vertrauenswürdigen Geräten überspringen"),
|
("enable-trusted-devices-tip", "2FA-Verifizierung auf vertrauenswürdigen Geräten überspringen"),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", "Plataforma"),
|
("Platform", "Plataforma"),
|
||||||
("Days remaining", "Días restantes"),
|
("Days remaining", "Días restantes"),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", "Piattaforma"),
|
("Platform", "Piattaforma"),
|
||||||
("Days remaining", "Giorni rimanenti"),
|
("Days remaining", "Giorni rimanenti"),
|
||||||
("enable-trusted-devices-tip", "Salta verifica 2FA nei dispositivi attendibili"),
|
("enable-trusted-devices-tip", "Salta verifica 2FA nei dispositivi attendibili"),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", "플랫폼"),
|
("Platform", "플랫폼"),
|
||||||
("Days remaining", "일 남음"),
|
("Days remaining", "일 남음"),
|
||||||
("enable-trusted-devices-tip", "신뢰할 수 있는 기기에서 2FA 검증 건너뛰기"),
|
("enable-trusted-devices-tip", "신뢰할 수 있는 기기에서 2FA 검증 건너뛰기"),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -641,5 +641,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Platform", ""),
|
("Platform", ""),
|
||||||
("Days remaining", ""),
|
("Days remaining", ""),
|
||||||
("enable-trusted-devices-tip", ""),
|
("enable-trusted-devices-tip", ""),
|
||||||
|
("Parent directory", ""),
|
||||||
|
("Resume", ""),
|
||||||
|
("Invalid file name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -2274,6 +2274,22 @@ impl Connection {
|
|||||||
job.confirm(&r);
|
job.confirm(&r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(file_action::Union::Rename(r)) => {
|
||||||
|
self.send_fs(ipc::FS::Rename {
|
||||||
|
id: r.id,
|
||||||
|
path: r.path.clone(),
|
||||||
|
new_name: r.new_name.clone(),
|
||||||
|
});
|
||||||
|
self.send_to_cm(ipc::Data::FileTransferLog((
|
||||||
|
"rename".to_string(),
|
||||||
|
serde_json::to_string(&FileRenameLog {
|
||||||
|
conn_id: self.inner.id(),
|
||||||
|
path: r.path,
|
||||||
|
new_name: r.new_name,
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3451,6 +3467,14 @@ struct FileActionLog {
|
|||||||
dir: bool,
|
dir: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct FileRenameLog {
|
||||||
|
conn_id: i32,
|
||||||
|
path: String,
|
||||||
|
new_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
struct FileRemoveLogControl {
|
struct FileRemoveLogControl {
|
||||||
conn_id: i32,
|
conn_id: i32,
|
||||||
instant: Instant,
|
instant: Instant,
|
||||||
|
@ -881,6 +881,9 @@ async fn handle_fs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ipc::FS::Rename { id, path, new_name } => {
|
||||||
|
rename_file(path, new_name, id, tx).await;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -945,6 +948,17 @@ async fn create_dir(path: String, id: i32, tx: &UnboundedSender<Data>) {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "ios")))]
|
||||||
|
async fn rename_file(path: String, new_name: String, id: i32, tx: &UnboundedSender<Data>) {
|
||||||
|
handle_result(
|
||||||
|
spawn_blocking(move || fs::rename_file(&path, &new_name)).await,
|
||||||
|
id,
|
||||||
|
0,
|
||||||
|
tx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "ios")))]
|
#[cfg(not(any(target_os = "ios")))]
|
||||||
async fn remove_dir(path: String, id: i32, recursive: bool, tx: &UnboundedSender<Data>) {
|
async fn remove_dir(path: String, id: i32, recursive: bool, tx: &UnboundedSender<Data>) {
|
||||||
let path = fs::get_path(&path);
|
let path = fs::get_path(&path);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user