Merge pull request #876 from Kingtous/flutter_desktop
add: file transfer dual logic with bridge
This commit is contained in:
commit
1fc8957c1c
@ -11,7 +11,6 @@ import 'package:provider/provider.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import '../../mobile/widgets/dialog.dart';
|
||||
import '../../models/model.dart';
|
||||
|
||||
class FileManagerPage extends StatefulWidget {
|
||||
@ -25,7 +24,8 @@ class FileManagerPage extends StatefulWidget {
|
||||
class _FileManagerPageState extends State<FileManagerPage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
final _selectedItems = SelectedItems();
|
||||
final _breadCrumbScroller = ScrollController();
|
||||
final _breadCrumbLocalScroller = ScrollController();
|
||||
final _breadCrumbRemoteScroller = ScrollController();
|
||||
|
||||
/// FFI with name file_transfer_id
|
||||
FFI get _ffi => ffi('ft_${widget.id}');
|
||||
@ -66,135 +66,11 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
onWillPop: () async {
|
||||
if (model.selectMode) {
|
||||
model.toggleSelectMode();
|
||||
} else {
|
||||
goBack();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: MyTheme.grayBg,
|
||||
appBar: AppBar(
|
||||
leading: Row(children: [
|
||||
IconButton(icon: Icon(Icons.close), onPressed: clientClose),
|
||||
]),
|
||||
centerTitle: true,
|
||||
// title: ToggleSwitch(
|
||||
// initialLabelIndex: model.isLocal ? 0 : 1,
|
||||
// activeBgColor: [MyTheme.idColor],
|
||||
// inactiveBgColor: MyTheme.grayBg,
|
||||
// inactiveFgColor: Colors.black54,
|
||||
// totalSwitches: 2,
|
||||
// minWidth: 100,
|
||||
// fontSize: 15,
|
||||
// iconSize: 18,
|
||||
// labels: [translate("Local"), translate("Remote")],
|
||||
// icons: [Icons.phone_android_sharp, Icons.screen_share],
|
||||
// onToggle: (index) {
|
||||
// final current = model.isLocal ? 0 : 1;
|
||||
// if (index != current) {
|
||||
// model.togglePage();
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
actions: [
|
||||
PopupMenuButton<String>(
|
||||
icon: Icon(Icons.more_vert),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.refresh, color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Refresh File"))
|
||||
],
|
||||
),
|
||||
value: "refresh",
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.check, color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Multi Select"))
|
||||
],
|
||||
),
|
||||
value: "select",
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.folder_outlined,
|
||||
color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Create Folder"))
|
||||
],
|
||||
),
|
||||
value: "folder",
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
model.currentShowHidden
|
||||
? Icons.check_box_outlined
|
||||
: Icons.check_box_outline_blank,
|
||||
color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Show Hidden Files"))
|
||||
],
|
||||
),
|
||||
value: "hidden",
|
||||
)
|
||||
];
|
||||
},
|
||||
onSelected: (v) {
|
||||
if (v == "refresh") {
|
||||
model.refresh();
|
||||
} else if (v == "select") {
|
||||
_selectedItems.clear();
|
||||
model.toggleSelectMode();
|
||||
} else if (v == "folder") {
|
||||
final name = TextEditingController();
|
||||
DialogManager.show((setState, close) =>
|
||||
CustomAlertDialog(
|
||||
title: Text(translate("Create Folder")),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: translate(
|
||||
"Please enter the folder name"),
|
||||
),
|
||||
controller: name,
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(false),
|
||||
child: Text(translate("Cancel"))),
|
||||
ElevatedButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () {
|
||||
if (name.value.text.isNotEmpty) {
|
||||
model.createDir(PathUtil.join(
|
||||
model.currentDir.path,
|
||||
name.value.text,
|
||||
model.currentIsWindows));
|
||||
close();
|
||||
}
|
||||
},
|
||||
child: Text(translate("OK")))
|
||||
]));
|
||||
} else if (v == "hidden") {
|
||||
model.toggleShowHidden();
|
||||
}
|
||||
}),
|
||||
],
|
||||
),
|
||||
body: Row(
|
||||
children: [
|
||||
Flexible(flex: 1, child: body(isLocal: true)),
|
||||
@ -213,11 +89,110 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
return !_selectedItems.isOtherPage(model.isLocal);
|
||||
}
|
||||
|
||||
Widget menu({bool isLocal = false}) {
|
||||
return PopupMenuButton<String>(
|
||||
icon: Icon(Icons.more_vert),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.refresh, color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Refresh File"))
|
||||
],
|
||||
),
|
||||
value: "refresh",
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.check, color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Multi Select"))
|
||||
],
|
||||
),
|
||||
value: "select",
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.folder_outlined,
|
||||
color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Create Folder"))
|
||||
],
|
||||
),
|
||||
value: "folder",
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
model.currentShowHidden
|
||||
? Icons.check_box_outlined
|
||||
: Icons.check_box_outline_blank,
|
||||
color: Colors.black),
|
||||
SizedBox(width: 5),
|
||||
Text(translate("Show Hidden Files"))
|
||||
],
|
||||
),
|
||||
value: "hidden",
|
||||
)
|
||||
];
|
||||
},
|
||||
onSelected: (v) {
|
||||
if (v == "refresh") {
|
||||
model.refresh();
|
||||
} else if (v == "select") {
|
||||
_selectedItems.clear();
|
||||
model.toggleSelectMode();
|
||||
} else if (v == "folder") {
|
||||
final name = TextEditingController();
|
||||
DialogManager.show((setState, close) =>
|
||||
CustomAlertDialog(
|
||||
title: Text(translate("Create Folder")),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: translate(
|
||||
"Please enter the folder name"),
|
||||
),
|
||||
controller: name,
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(false),
|
||||
child: Text(translate("Cancel"))),
|
||||
ElevatedButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () {
|
||||
if (name.value.text.isNotEmpty) {
|
||||
model.createDir(PathUtil.join(
|
||||
model.currentDir.path,
|
||||
name.value.text,
|
||||
model.currentIsWindows));
|
||||
close();
|
||||
}
|
||||
},
|
||||
child: Text(translate("OK")))
|
||||
]));
|
||||
} else if (v == "hidden") {
|
||||
model.toggleShowHidden(local: isLocal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget body({bool isLocal = false}) {
|
||||
final fd = isLocal ? model.currentLocalDir : model.currentRemoteDir;
|
||||
final entries = fd.entries;
|
||||
return Column(children: [
|
||||
headTools(),
|
||||
headTools(isLocal),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: entries.length + 1,
|
||||
@ -301,8 +276,8 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
return;
|
||||
}
|
||||
if (entries[index].isDirectory) {
|
||||
model.openDirectory(entries[index].path);
|
||||
breadCrumbScrollToEnd();
|
||||
model.openDirectory(entries[index].path, isLocal: isLocal);
|
||||
breadCrumbScrollToEnd(isLocal);
|
||||
} else {
|
||||
// Perform file-related tasks.
|
||||
}
|
||||
@ -322,20 +297,21 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
]);
|
||||
}
|
||||
|
||||
goBack() {
|
||||
model.goToParentDirectory();
|
||||
goBack({bool? isLocal}) {
|
||||
model.goToParentDirectory(isLocal: isLocal);
|
||||
}
|
||||
|
||||
breadCrumbScrollToEnd() {
|
||||
breadCrumbScrollToEnd(bool isLocal) {
|
||||
final controller = isLocal ? _breadCrumbLocalScroller : _breadCrumbRemoteScroller;
|
||||
Future.delayed(Duration(milliseconds: 200), () {
|
||||
_breadCrumbScroller.animateTo(
|
||||
_breadCrumbScroller.position.maxScrollExtent,
|
||||
controller.animateTo(
|
||||
controller.position.maxScrollExtent,
|
||||
duration: Duration(milliseconds: 200),
|
||||
curve: Curves.fastLinearToSlowEaseIn);
|
||||
});
|
||||
}
|
||||
|
||||
Widget headTools() => Container(
|
||||
Widget headTools(bool isLocal) => Container(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@ -353,16 +329,18 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
path = PathUtil.join(path, item, model.currentIsWindows);
|
||||
}
|
||||
}
|
||||
model.openDirectory(path);
|
||||
}),
|
||||
model.openDirectory(path, isLocal: isLocal);
|
||||
}, isLocal),
|
||||
divider: Icon(Icons.chevron_right),
|
||||
overflow: ScrollableOverflow(controller: _breadCrumbScroller),
|
||||
overflow: ScrollableOverflow(controller: isLocal ? _breadCrumbLocalScroller : _breadCrumbRemoteScroller),
|
||||
)),
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.arrow_upward),
|
||||
onPressed: goBack,
|
||||
onPressed: () {
|
||||
goBack(isLocal: isLocal);
|
||||
},
|
||||
),
|
||||
PopupMenuButton<SortBy>(
|
||||
icon: Icon(Icons.sort),
|
||||
@ -375,7 +353,10 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
))
|
||||
.toList();
|
||||
},
|
||||
onSelected: model.changeSortStyle),
|
||||
onSelected: (sort) {
|
||||
model.changeSortStyle(sort, isLocal: isLocal);
|
||||
}),
|
||||
menu(isLocal: isLocal)
|
||||
],
|
||||
)
|
||||
],
|
||||
@ -486,8 +467,8 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
}
|
||||
|
||||
List<BreadCrumbItem> getPathBreadCrumbItems(
|
||||
void Function() onHome, void Function(List<String>) onPressed) {
|
||||
final path = model.currentShortPath;
|
||||
void Function() onHome, void Function(List<String>) onPressed, bool isLocal) {
|
||||
final path = model.shortPath(isLocal);
|
||||
final list = PathUtil.split(path, model.currentIsWindows);
|
||||
final breadCrumbList = [
|
||||
BreadCrumbItem(
|
||||
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/file_manager_page.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/titlebar_widget.dart';
|
||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
/// File Transfer for multi tabs
|
||||
class FileManagerTabPage extends StatefulWidget {
|
||||
@ -21,7 +22,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
|
||||
// refactor List<int> when using multi-tab
|
||||
// this singleton is only for test
|
||||
List<String> connectionIds = List.empty(growable: true);
|
||||
var initialIndex = 0;
|
||||
var initialIndex = 0.obs;
|
||||
|
||||
_FileManagerTabPageState(Map<String, dynamic> params) {
|
||||
if (params['id'] != null) {
|
||||
@ -37,21 +38,15 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
|
||||
"call ${call.method} with args ${call.arguments} from window ${fromWindowId}");
|
||||
// for simplify, just replace connectionId
|
||||
if (call.method == "new_file_transfer") {
|
||||
setState(() {
|
||||
final args = jsonDecode(call.arguments);
|
||||
final id = args['id'];
|
||||
final indexOf = connectionIds.indexOf(id);
|
||||
if (indexOf >= 0) {
|
||||
setState(() {
|
||||
initialIndex = indexOf;
|
||||
});
|
||||
} else {
|
||||
connectionIds.add(id);
|
||||
setState(() {
|
||||
initialIndex = connectionIds.length - 1;
|
||||
});
|
||||
}
|
||||
});
|
||||
final args = jsonDecode(call.arguments);
|
||||
final id = args['id'];
|
||||
final indexOf = connectionIds.indexOf(id);
|
||||
if (indexOf >= 0) {
|
||||
initialIndex.value = indexOf;
|
||||
} else {
|
||||
connectionIds.add(id);
|
||||
initialIndex.value = connectionIds.length - 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -59,51 +54,53 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: DefaultTabController(
|
||||
initialIndex: initialIndex,
|
||||
length: connectionIds.length,
|
||||
animationDuration: Duration.zero,
|
||||
child: Column(
|
||||
children: [
|
||||
DesktopTitleBar(
|
||||
child: TabBar(
|
||||
isScrollable: true,
|
||||
labelColor: Colors.white,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
indicatorColor: Colors.white,
|
||||
tabs: connectionIds
|
||||
.map((e) => Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(e),
|
||||
SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
onRemoveId(e);
|
||||
},
|
||||
child: Icon(
|
||||
Icons.highlight_remove,
|
||||
size: 20,
|
||||
))
|
||||
],
|
||||
),
|
||||
))
|
||||
.toList()),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
children: connectionIds
|
||||
.map((e) => Container(
|
||||
child: FileManagerPage(
|
||||
key: ValueKey(e),
|
||||
id: e))) //RemotePage(key: ValueKey(e), id: e))
|
||||
.toList()),
|
||||
)
|
||||
],
|
||||
body: Obx(
|
||||
()=> DefaultTabController(
|
||||
initialIndex: initialIndex.value,
|
||||
length: connectionIds.length,
|
||||
animationDuration: Duration.zero,
|
||||
child: Column(
|
||||
children: [
|
||||
DesktopTitleBar(
|
||||
child: TabBar(
|
||||
isScrollable: true,
|
||||
labelColor: Colors.white,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
indicatorColor: Colors.white,
|
||||
tabs: connectionIds
|
||||
.map((e) => Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(e),
|
||||
SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
onRemoveId(e);
|
||||
},
|
||||
child: Icon(
|
||||
Icons.highlight_remove,
|
||||
size: 20,
|
||||
))
|
||||
],
|
||||
),
|
||||
))
|
||||
.toList()),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
children: connectionIds
|
||||
.map((e) => Container(
|
||||
child: FileManagerPage(
|
||||
key: ValueKey(e),
|
||||
id: e))) //RemotePage(key: ValueKey(e), id: e))
|
||||
.toList()),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -114,9 +111,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
|
||||
if (indexOf == -1) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
connectionIds.removeAt(indexOf);
|
||||
initialIndex = max(0, initialIndex - 1);
|
||||
});
|
||||
connectionIds.removeAt(indexOf);
|
||||
initialIndex.value = max(0, initialIndex.value - 1);
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,21 @@ class FileModel extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
String shortPath(bool isLocal) {
|
||||
final dir = isLocal ? currentLocalDir : currentRemoteDir;
|
||||
if (dir.path.startsWith(currentHome)) {
|
||||
var path = dir.path.replaceFirst(currentHome, "");
|
||||
if (path.length == 0) return "";
|
||||
if (path[0] == "/" || path[0] == "\\") {
|
||||
// remove more '/' or '\'
|
||||
path = path.replaceFirst(path[0], "");
|
||||
}
|
||||
return path;
|
||||
} else {
|
||||
return dir.path.replaceFirst(currentHome, "");
|
||||
}
|
||||
}
|
||||
|
||||
bool get currentShowHidden =>
|
||||
_isLocal ? _localOption.showHidden : _remoteOption.showHidden;
|
||||
|
||||
@ -265,9 +280,9 @@ class FileModel extends ChangeNotifier {
|
||||
openDirectory(currentHome);
|
||||
}
|
||||
|
||||
goToParentDirectory() {
|
||||
goToParentDirectory({bool? isLocal}) {
|
||||
final parent = PathUtil.dirname(currentDir.path, currentIsWindows);
|
||||
openDirectory(parent);
|
||||
openDirectory(parent, isLocal: isLocal);
|
||||
}
|
||||
|
||||
sendFiles(SelectedItems items) {
|
||||
@ -282,17 +297,10 @@ class FileModel extends ChangeNotifier {
|
||||
items.isLocal! ? _localOption.isWindows : _remoteOption.isWindows;
|
||||
final showHidden =
|
||||
items.isLocal! ? _localOption.showHidden : _remoteOption.showHidden;
|
||||
items.items.forEach((from) {
|
||||
items.items.forEach((from) async {
|
||||
_jobId++;
|
||||
final msg = {
|
||||
"id": _jobId.toString(),
|
||||
"path": from.path,
|
||||
"to": PathUtil.join(toPath, from.name, isWindows),
|
||||
"file_num": "0",
|
||||
"show_hidden": showHidden.toString(),
|
||||
"is_remote": (!(items.isLocal!)).toString()
|
||||
};
|
||||
_ffi.target?.setByName("send_files", jsonEncode(msg));
|
||||
await _ffi.target?.bind.sessionSendFiles(id: '${_ffi.target?.getId()}', actId: _jobId, path: from.path, to: PathUtil.join(toPath, from.name, isWindows)
|
||||
,fileNum: 0, includeHidden: showHidden, isRemote: !(items.isLocal!));
|
||||
});
|
||||
}
|
||||
|
||||
@ -485,43 +493,34 @@ class FileModel extends ChangeNotifier {
|
||||
}
|
||||
|
||||
sendRemoveFile(String path, int fileNum, bool isLocal) {
|
||||
final msg = {
|
||||
"id": _jobId.toString(),
|
||||
"path": path,
|
||||
"file_num": fileNum.toString(),
|
||||
"is_remote": (!(isLocal)).toString()
|
||||
};
|
||||
_ffi.target?.setByName("remove_file", jsonEncode(msg));
|
||||
_ffi.target?.bind.sessionRemoveFile(id: '${_ffi.target?.getId()}', actId: _jobId, path: path, isRemote: !isLocal, fileNum: fileNum);
|
||||
}
|
||||
|
||||
sendRemoveEmptyDir(String path, int fileNum, bool isLocal) {
|
||||
final msg = {
|
||||
"id": _jobId.toString(),
|
||||
"path": path,
|
||||
"is_remote": (!isLocal).toString()
|
||||
};
|
||||
_ffi.target?.setByName("remove_all_empty_dirs", jsonEncode(msg));
|
||||
_ffi.target?.bind.sessionRemoveAllEmptyDirs(id: '${_ffi.target?.getId()}', actId: _jobId, path: path, isRemote: !isLocal);
|
||||
}
|
||||
|
||||
createDir(String path) {
|
||||
createDir(String path) async {
|
||||
_jobId++;
|
||||
final msg = {
|
||||
"id": _jobId.toString(),
|
||||
"path": path,
|
||||
"is_remote": (!isLocal).toString()
|
||||
};
|
||||
_ffi.target?.setByName("create_dir", jsonEncode(msg));
|
||||
_ffi.target?.bind.sessionCreateDir(id: '${_ffi.target?.getId()}', actId: _jobId, path: path, isRemote: !isLocal);
|
||||
}
|
||||
|
||||
cancelJob(int id) {
|
||||
_ffi.target?.setByName("cancel_job", id.toString());
|
||||
cancelJob(int id) async {
|
||||
_ffi.target?.bind.sessionCancelJob(id: '${_ffi.target?.getId()}', actId: id);
|
||||
jobReset();
|
||||
}
|
||||
|
||||
changeSortStyle(SortBy sort) {
|
||||
changeSortStyle(SortBy sort, {bool? isLocal}) {
|
||||
_sortStyle = sort;
|
||||
_currentLocalDir.changeSortStyle(sort);
|
||||
_currentRemoteDir.changeSortStyle(sort);
|
||||
if (isLocal == null) {
|
||||
// compatible for mobile logic
|
||||
_currentLocalDir.changeSortStyle(sort);
|
||||
_currentRemoteDir.changeSortStyle(sort);
|
||||
} else if (isLocal) {
|
||||
_currentLocalDir.changeSortStyle(sort);
|
||||
} else {
|
||||
_currentRemoteDir.changeSortStyle(sort);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ class RustDeskMultiWindowManager {
|
||||
case WindowType.RemoteDesktop:
|
||||
return _remoteDesktopWindowId;
|
||||
case WindowType.FileTransfer:
|
||||
break;
|
||||
return _fileTransferWindowId;
|
||||
case WindowType.PortForward:
|
||||
break;
|
||||
case WindowType.Unknown:
|
||||
|
Loading…
x
Reference in New Issue
Block a user