Files
rustdesk/flutter/lib/desktop/pages/file_manager_tab_page.dart
T
21pages 956031d109 feat: add connections without sending passwords
Add Without password actions and pass the selection through desktop,
mobile and Web sessions. Omit the password when constructing LoginRequest,
preserve saved credentials, and reuse the existing approval and OS login
dialogs. Keep protocol and controlled-side authentication changes separate.
2026-10-31 12:08:07 +08:00

180 lines
5.8 KiB
Dart

import 'dart:convert';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/common/widgets/dialog.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/models/state_model.dart';
import 'package:flutter_hbb/desktop/pages/file_manager_page.dart';
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:get/get.dart';
import '../../models/platform_model.dart';
/// File Transfer for multi tabs
class FileManagerTabPage extends StatefulWidget {
final Map<String, dynamic> params;
const FileManagerTabPage({Key? key, required this.params}) : super(key: key);
@override
State<FileManagerTabPage> createState() => _FileManagerTabPageState(params);
}
class _FileManagerTabPageState extends State<FileManagerTabPage> {
DesktopTabController get tabController => Get.find<DesktopTabController>();
static const IconData selectedIcon = Icons.file_copy_sharp;
static const IconData unselectedIcon = Icons.file_copy_outlined;
_FileManagerTabPageState(Map<String, dynamic> params) {
Get.put(DesktopTabController(tabType: DesktopTabType.fileTransfer));
tabController.onSelected = (id) {
WindowController.fromWindowId(windowId())
.setTitle(getWindowNameWithId(id));
};
tabController.onRemoved = (_, id) => onRemoveId(id);
tabController.add(TabInfo(
key: params['id'],
label: params['id'],
selectedIcon: selectedIcon,
unselectedIcon: unselectedIcon,
onTabCloseButton: () async {
if (await desktopTryShowTabAuditDialogCloseCancelled(
id: params['id'],
tabController: tabController,
)) {
return;
}
tabController.closeBy(params['id']);
},
page: FileManagerPage(
key: ValueKey(params['id']),
id: params['id'],
password: params['password'],
loginMethod: params['loginMethod'] ?? '',
isSharedPassword: params['isSharedPassword'],
tabController: tabController,
forceRelay: params['forceRelay'],
connToken: params['connToken'],
)));
}
@override
void initState() {
super.initState();
rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
debugPrint(
"[FileTransfer] call ${call.method} with args ${call.arguments} from window $fromWindowId to ${windowId()}");
// for simplify, just replace connectionId
if (call.method == kWindowEventNewFileTransfer) {
final args = jsonDecode(call.arguments);
final id = args['id'];
windowOnTop(windowId());
tabController.add(TabInfo(
key: id,
label: id,
selectedIcon: selectedIcon,
unselectedIcon: unselectedIcon,
onTabCloseButton: () async {
if (await desktopTryShowTabAuditDialogCloseCancelled(
id: id,
tabController: tabController,
)) {
return;
}
tabController.closeBy(id);
},
page: FileManagerPage(
key: ValueKey(id),
id: id,
password: args['password'],
loginMethod: args['loginMethod'] ?? '',
isSharedPassword: args['isSharedPassword'],
tabController: tabController,
forceRelay: args['forceRelay'],
connToken: args['connToken'],
)));
} else if (call.method == "onDestroy") {
tabController.clear();
} else if (call.method == kWindowActionRebuild) {
reloadCurrentWindow();
}
});
Future.delayed(Duration.zero, () {
restoreWindowPosition(WindowType.FileTransfer, windowId: windowId());
});
}
@override
Widget build(BuildContext context) {
final child = Scaffold(
backgroundColor: Theme.of(context).cardColor,
body: DesktopTab(
controller: tabController,
onWindowCloseButton: handleWindowCloseButton,
tail: const AddButton(),
selectedBorderColor: MyTheme.accent,
labelGetter: DesktopTab.tablabelGetter,
));
final tabWidget = isLinux
? buildVirtualWindowFrame(context, child)
: workaroundWindowBorder(
context,
Container(
decoration: BoxDecoration(
border: Border.all(color: MyTheme.color(context).border!)),
child: child,
));
return isMacOS || kUseCompatibleUiMode
? tabWidget
: SubWindowDragToResizeArea(
child: tabWidget,
resizeEdgeSize: stateGlobal.resizeEdgeSize.value,
enableResizeEdges: subWindowManagerEnableResizeEdges,
windowId: stateGlobal.windowId,
);
}
void onRemoveId(String id) {
if (tabController.state.value.tabs.isEmpty) {
WindowController.fromWindowId(windowId()).close();
}
}
int windowId() {
return widget.params["windowId"];
}
Future<bool> handleWindowCloseButton() async {
final connLength = tabController.state.value.tabs.length;
if (connLength == 1) {
if (await desktopTryShowTabAuditDialogCloseCancelled(
id: tabController.state.value.tabs[0].key,
tabController: tabController,
)) {
return false;
}
}
if (connLength <= 1) {
tabController.clear();
return true;
} else {
final bool res;
if (!option2bool(kOptionEnableConfirmClosingTabs,
bind.mainGetLocalOption(key: kOptionEnableConfirmClosingTabs))) {
res = true;
} else {
res = await closeConfirmDialog();
}
if (res) {
tabController.clear();
}
return res;
}
}
}