mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge pull request #1389 from 21pages/port-forward
port forward ui && fix TextField cursor problem
This commit is contained in:
@@ -806,6 +806,8 @@ Future<bool> loginDialog() async {
|
||||
var userNameMsg = "";
|
||||
String pass = "";
|
||||
var passMsg = "";
|
||||
var userContontroller = TextEditingController(text: userName);
|
||||
var pwdController = TextEditingController(text: pass);
|
||||
|
||||
var isInProgress = false;
|
||||
var completer = Completer<bool>();
|
||||
@@ -833,13 +835,10 @@ Future<bool> loginDialog() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
userName = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorText: userNameMsg.isNotEmpty ? userNameMsg : null),
|
||||
controller: TextEditingController(text: userName),
|
||||
controller: userContontroller,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -859,13 +858,10 @@ Future<bool> loginDialog() async {
|
||||
Expanded(
|
||||
child: TextField(
|
||||
obscureText: true,
|
||||
onChanged: (s) {
|
||||
pass = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorText: passMsg.isNotEmpty ? passMsg : null),
|
||||
controller: TextEditingController(text: pass),
|
||||
controller: pwdController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -896,8 +892,8 @@ Future<bool> loginDialog() async {
|
||||
isInProgress = false;
|
||||
});
|
||||
};
|
||||
userName = userName;
|
||||
pass = pass;
|
||||
userName = userContontroller.text;
|
||||
pass = pwdController.text;
|
||||
if (userName.isEmpty) {
|
||||
userNameMsg = translate("Username missed");
|
||||
cancel();
|
||||
|
||||
@@ -1025,7 +1025,6 @@ class _ComboBox extends StatelessWidget {
|
||||
|
||||
void changeServer() async {
|
||||
Map<String, dynamic> oldOptions = jsonDecode(await bind.mainGetOptions());
|
||||
print("${oldOptions}");
|
||||
String idServer = oldOptions['custom-rendezvous-server'] ?? "";
|
||||
var idServerMsg = "";
|
||||
String relayServer = oldOptions['relay-server'] ?? "";
|
||||
@@ -1033,6 +1032,10 @@ void changeServer() async {
|
||||
String apiServer = oldOptions['api-server'] ?? "";
|
||||
var apiServerMsg = "";
|
||||
var key = oldOptions['key'] ?? "";
|
||||
var idController = TextEditingController(text: idServer);
|
||||
var relayController = TextEditingController(text: relayServer);
|
||||
var apiController = TextEditingController(text: apiServer);
|
||||
var keyController = TextEditingController(text: key);
|
||||
|
||||
var isInProgress = false;
|
||||
gFFI.dialogManager.show((setState, close) {
|
||||
@@ -1057,13 +1060,10 @@ void changeServer() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
idServer = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorText: idServerMsg.isNotEmpty ? idServerMsg : null),
|
||||
controller: TextEditingController(text: idServer),
|
||||
controller: idController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1082,14 +1082,11 @@ void changeServer() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
relayServer = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorText:
|
||||
relayServerMsg.isNotEmpty ? relayServerMsg : null),
|
||||
controller: TextEditingController(text: relayServer),
|
||||
controller: relayController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1108,14 +1105,11 @@ void changeServer() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
apiServer = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorText:
|
||||
apiServerMsg.isNotEmpty ? apiServerMsg : null),
|
||||
controller: TextEditingController(text: apiServer),
|
||||
controller: apiController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1134,13 +1128,10 @@ void changeServer() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
key = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
controller: TextEditingController(text: key),
|
||||
controller: keyController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1171,10 +1162,10 @@ void changeServer() async {
|
||||
isInProgress = false;
|
||||
});
|
||||
};
|
||||
idServer = idServer.trim();
|
||||
relayServer = relayServer.trim();
|
||||
apiServer = apiServer.trim();
|
||||
key = key.trim();
|
||||
idServer = idController.text.trim();
|
||||
relayServer = relayController.text.trim();
|
||||
apiServer = apiController.text.trim().toLowerCase();
|
||||
key = keyController.text.trim();
|
||||
|
||||
if (idServer.isNotEmpty) {
|
||||
idServerMsg = translate(
|
||||
@@ -1230,6 +1221,7 @@ void changeWhiteList() async {
|
||||
Map<String, dynamic> oldOptions = jsonDecode(await bind.mainGetOptions());
|
||||
var newWhiteList = ((oldOptions['whitelist'] ?? "") as String).split(',');
|
||||
var newWhiteListField = newWhiteList.join('\n');
|
||||
var controller = TextEditingController(text: newWhiteListField);
|
||||
var msg = "";
|
||||
var isInProgress = false;
|
||||
gFFI.dialogManager.show((setState, close) {
|
||||
@@ -1246,15 +1238,12 @@ void changeWhiteList() async {
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
newWhiteListField = s;
|
||||
},
|
||||
maxLines: null,
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorText: msg.isEmpty ? null : translate(msg),
|
||||
),
|
||||
controller: TextEditingController(text: newWhiteListField),
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1277,7 +1266,7 @@ void changeWhiteList() async {
|
||||
msg = "";
|
||||
isInProgress = true;
|
||||
});
|
||||
newWhiteListField = newWhiteListField.trim();
|
||||
newWhiteListField = controller.text.trim();
|
||||
var newWhiteList = "";
|
||||
if (newWhiteListField.isEmpty) {
|
||||
// pass
|
||||
@@ -1319,6 +1308,9 @@ void changeSocks5Proxy() async {
|
||||
username = socks[1];
|
||||
password = socks[2];
|
||||
}
|
||||
var proxyController = TextEditingController(text: proxy);
|
||||
var userController = TextEditingController(text: username);
|
||||
var pwdController = TextEditingController(text: password);
|
||||
|
||||
var isInProgress = false;
|
||||
gFFI.dialogManager.show((setState, close) {
|
||||
@@ -1343,13 +1335,10 @@ void changeSocks5Proxy() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
proxy = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorText: proxyMsg.isNotEmpty ? proxyMsg : null),
|
||||
controller: TextEditingController(text: proxy),
|
||||
controller: proxyController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1368,13 +1357,10 @@ void changeSocks5Proxy() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
username = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
controller: TextEditingController(text: username),
|
||||
controller: userController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1393,13 +1379,10 @@ void changeSocks5Proxy() async {
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onChanged: (s) {
|
||||
password = s;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
controller: TextEditingController(text: password),
|
||||
controller: pwdController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1428,9 +1411,9 @@ void changeSocks5Proxy() async {
|
||||
isInProgress = false;
|
||||
});
|
||||
};
|
||||
proxy = proxy.trim();
|
||||
username = username.trim();
|
||||
password = password.trim();
|
||||
proxy = proxyController.text.trim();
|
||||
username = userController.text.trim();
|
||||
password = pwdController.text.trim();
|
||||
|
||||
if (proxy.isNotEmpty) {
|
||||
proxyMsg =
|
||||
|
||||
348
flutter/lib/desktop/pages/port_forward_page.dart
Normal file
348
flutter/lib/desktop/pages/port_forward_page.dart
Normal file
@@ -0,0 +1,348 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hbb/common.dart';
|
||||
import 'package:flutter_hbb/models/model.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
|
||||
const double _kColumn1Width = 30;
|
||||
const double _kColumn4Width = 100;
|
||||
const double _kRowHeight = 50;
|
||||
const double _kTextLeftMargin = 20;
|
||||
|
||||
class _PortForward {
|
||||
int localPort;
|
||||
String remoteHost;
|
||||
int remotePort;
|
||||
|
||||
_PortForward.fromJson(List<dynamic> json)
|
||||
: localPort = json[0] as int,
|
||||
remoteHost = json[1] as String,
|
||||
remotePort = json[2] as int;
|
||||
}
|
||||
|
||||
class PortForwardPage extends StatefulWidget {
|
||||
const PortForwardPage({Key? key, required this.id, required this.isRDP})
|
||||
: super(key: key);
|
||||
final String id;
|
||||
final bool isRDP;
|
||||
|
||||
@override
|
||||
State<PortForwardPage> createState() => _PortForwardPageState();
|
||||
}
|
||||
|
||||
class _PortForwardPageState extends State<PortForwardPage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
final bool isRdp = false;
|
||||
final TextEditingController localPortController = TextEditingController();
|
||||
final TextEditingController remoteHostController = TextEditingController();
|
||||
final TextEditingController remotePortController = TextEditingController();
|
||||
RxList<_PortForward> pfs = RxList.empty(growable: true);
|
||||
late FFI _ffi;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_ffi = FFI();
|
||||
// _ffi.connect(widget.id, isPortForward: true);
|
||||
Get.put(_ffi, tag: 'pf_${widget.id}');
|
||||
if (!Platform.isLinux) {
|
||||
Wakelock.enable();
|
||||
}
|
||||
print("init success with id ${widget.id}");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_ffi.close();
|
||||
_ffi.dialogManager.dismissAll();
|
||||
if (!Platform.isLinux) {
|
||||
Wakelock.disable();
|
||||
}
|
||||
Get.delete<FFI>(tag: 'pf_${widget.id}');
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return Scaffold(
|
||||
backgroundColor: MyTheme.color(context).grayBg,
|
||||
body: FutureBuilder(future: () async {
|
||||
if (!isRdp) {
|
||||
refreshTunnelConfig();
|
||||
}
|
||||
}(), builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 20, color: MyTheme.color(context).grayBg!)),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
buildPrompt(context),
|
||||
Flexible(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: MyTheme.color(context).bg,
|
||||
border: Border.all(width: 1, color: MyTheme.border)),
|
||||
child:
|
||||
widget.isRDP ? buildRdp(context) : buildTunnel(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return const Offstage();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
buildPrompt(BuildContext context) {
|
||||
return Obx(() => Offstage(
|
||||
offstage: pfs.isEmpty && !widget.isRDP,
|
||||
child: Container(
|
||||
height: 45,
|
||||
color: const Color(0xFF007F00),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
translate('Listening ...'),
|
||||
style: const TextStyle(fontSize: 16, color: Colors.white),
|
||||
),
|
||||
Text(
|
||||
translate('not_close_tcp_tip'),
|
||||
style: const TextStyle(
|
||||
fontSize: 10, color: Color(0xFFDDDDDD), height: 1.2),
|
||||
)
|
||||
])).marginOnly(bottom: 8),
|
||||
));
|
||||
}
|
||||
|
||||
buildTunnel(BuildContext context) {
|
||||
text(String lable) => Expanded(
|
||||
child: Text(translate(lable)).marginOnly(left: _kTextLeftMargin));
|
||||
|
||||
return Theme(
|
||||
data: Theme.of(context)
|
||||
.copyWith(backgroundColor: MyTheme.color(context).bg),
|
||||
child: Obx(() => ListView.builder(
|
||||
itemCount: pfs.length + 2,
|
||||
itemBuilder: ((context, index) {
|
||||
if (index == 0) {
|
||||
return Container(
|
||||
height: 25,
|
||||
color: MyTheme.color(context).grayBg,
|
||||
child: Row(children: [
|
||||
text('Local Port'),
|
||||
const SizedBox(width: _kColumn1Width),
|
||||
text('Remote Host'),
|
||||
text('Remote Port'),
|
||||
SizedBox(
|
||||
width: _kColumn4Width, child: Text(translate('Action')))
|
||||
]),
|
||||
);
|
||||
} else if (index == 1) {
|
||||
return buildTunnelAddRow(context);
|
||||
} else {
|
||||
return buildTunnelDataRow(context, pfs[index - 2], index - 2);
|
||||
}
|
||||
}))),
|
||||
);
|
||||
}
|
||||
|
||||
buildTunnelAddRow(BuildContext context) {
|
||||
var portInputFormatter = [
|
||||
FilteringTextInputFormatter.allow(RegExp(
|
||||
r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$'))
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: _kRowHeight,
|
||||
decoration: BoxDecoration(color: MyTheme.color(context).bg),
|
||||
child: Row(children: [
|
||||
buildTunnelInputCell(context,
|
||||
controller: localPortController,
|
||||
inputFormatters: portInputFormatter),
|
||||
const SizedBox(
|
||||
width: _kColumn1Width, child: Icon(Icons.arrow_forward_sharp)),
|
||||
buildTunnelInputCell(context,
|
||||
controller: remoteHostController, hint: 'localhost'),
|
||||
buildTunnelInputCell(context,
|
||||
controller: remotePortController,
|
||||
inputFormatters: portInputFormatter),
|
||||
SizedBox(
|
||||
width: _kColumn4Width,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0, side: const BorderSide(color: MyTheme.border)),
|
||||
onPressed: () async {
|
||||
int? localPort = int.tryParse(localPortController.text);
|
||||
int? remotePort = int.tryParse(remotePortController.text);
|
||||
if (localPort != null &&
|
||||
remotePort != null &&
|
||||
(remoteHostController.text.isEmpty ||
|
||||
remoteHostController.text.trim().isNotEmpty)) {
|
||||
await bind.mainAddPortForward(
|
||||
id: widget.id,
|
||||
localPort: localPort,
|
||||
remoteHost: remoteHostController.text.trim().isEmpty
|
||||
? 'localhost'
|
||||
: remoteHostController.text.trim(),
|
||||
remotePort: remotePort);
|
||||
localPortController.clear();
|
||||
remoteHostController.clear();
|
||||
remotePortController.clear();
|
||||
refreshTunnelConfig();
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
translate('Add'),
|
||||
),
|
||||
).marginAll(10),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
buildTunnelInputCell(BuildContext context,
|
||||
{required TextEditingController controller,
|
||||
List<TextInputFormatter>? inputFormatters,
|
||||
String? hint}) {
|
||||
return Expanded(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
inputFormatters: inputFormatters,
|
||||
cursorColor: MyTheme.color(context).text,
|
||||
cursorHeight: 20,
|
||||
cursorWidth: 1,
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: MyTheme.color(context).border!)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: MyTheme.color(context).border!)),
|
||||
fillColor: MyTheme.color(context).bg,
|
||||
contentPadding: const EdgeInsets.all(10),
|
||||
hintText: hint,
|
||||
hintStyle: TextStyle(
|
||||
color: MyTheme.color(context).placeholder, fontSize: 16)),
|
||||
style: TextStyle(color: MyTheme.color(context).text, fontSize: 16),
|
||||
).marginAll(10),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTunnelDataRow(BuildContext context, _PortForward pf, int index) {
|
||||
text(String lable) => Expanded(
|
||||
child: Text(lable, style: const TextStyle(fontSize: 20))
|
||||
.marginOnly(left: _kTextLeftMargin));
|
||||
|
||||
return Container(
|
||||
height: _kRowHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: index % 2 == 0
|
||||
? isDarkTheme()
|
||||
? const Color(0xFF202020)
|
||||
: const Color(0xFFF4F5F6)
|
||||
: MyTheme.color(context).bg),
|
||||
child: Row(children: [
|
||||
text(pf.localPort.toString()),
|
||||
const SizedBox(width: _kColumn1Width),
|
||||
text(pf.remoteHost),
|
||||
text(pf.remotePort.toString()),
|
||||
SizedBox(
|
||||
width: _kColumn4Width,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () async {
|
||||
await bind.mainRemovePortForward(
|
||||
id: widget.id, localPort: pf.localPort);
|
||||
refreshTunnelConfig();
|
||||
},
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void refreshTunnelConfig() async {
|
||||
String peer = await bind.mainGetPeer(id: widget.id);
|
||||
Map<String, dynamic> config = jsonDecode(peer);
|
||||
List<dynamic> infos = config['port_forwards'] as List;
|
||||
List<_PortForward> result = List.empty(growable: true);
|
||||
for (var e in infos) {
|
||||
result.add(_PortForward.fromJson(e));
|
||||
}
|
||||
pfs.value = result;
|
||||
}
|
||||
|
||||
buildRdp(BuildContext context) {
|
||||
text1(String lable) =>
|
||||
Expanded(child: Text(lable).marginOnly(left: _kTextLeftMargin));
|
||||
text2(String lable) => Expanded(
|
||||
child: Text(
|
||||
lable,
|
||||
style: TextStyle(fontSize: 20),
|
||||
).marginOnly(left: _kTextLeftMargin));
|
||||
return Theme(
|
||||
data: Theme.of(context)
|
||||
.copyWith(backgroundColor: MyTheme.color(context).bg),
|
||||
child: ListView.builder(
|
||||
itemCount: 2,
|
||||
itemBuilder: ((context, index) {
|
||||
if (index == 0) {
|
||||
return Container(
|
||||
height: 25,
|
||||
color: MyTheme.color(context).grayBg,
|
||||
child: Row(children: [
|
||||
text1('Local Port'),
|
||||
const SizedBox(width: _kColumn1Width),
|
||||
text1('Remote Host'),
|
||||
text1('Remote Port'),
|
||||
]),
|
||||
);
|
||||
} else {
|
||||
return Container(
|
||||
height: _kRowHeight,
|
||||
decoration: BoxDecoration(color: MyTheme.color(context).bg),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SizedBox(
|
||||
width: 120,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
side: const BorderSide(color: MyTheme.border)),
|
||||
onPressed: () {},
|
||||
child: Text(
|
||||
translate('New RDP'),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w300, fontSize: 14),
|
||||
),
|
||||
).marginSymmetric(vertical: 10),
|
||||
).marginOnly(left: 20),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: _kColumn1Width,
|
||||
child: Icon(Icons.arrow_forward_sharp)),
|
||||
text2('localhost'),
|
||||
text2('RDP'),
|
||||
]),
|
||||
);
|
||||
}
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
}
|
||||
106
flutter/lib/desktop/pages/port_forward_tab_page.dart
Normal file
106
flutter/lib/desktop/pages/port_forward_tab_page.dart
Normal file
@@ -0,0 +1,106 @@
|
||||
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/desktop/pages/port_forward_page.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
|
||||
import 'package:flutter_hbb/models/model.dart';
|
||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class PortForwardTabPage extends StatefulWidget {
|
||||
final Map<String, dynamic> params;
|
||||
|
||||
const PortForwardTabPage({Key? key, required this.params}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<PortForwardTabPage> createState() => _PortForwardTabPageState(params);
|
||||
}
|
||||
|
||||
class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
||||
final tabController = Get.put(DesktopTabController());
|
||||
|
||||
static final IconData selectedIcon = Icons.forward_sharp;
|
||||
static final IconData unselectedIcon = Icons.forward_outlined;
|
||||
|
||||
_PortForwardTabPageState(Map<String, dynamic> params) {
|
||||
tabController.add(TabInfo(
|
||||
key: params['id'] + params['isRDP'].toString(),
|
||||
label: params['id'],
|
||||
selectedIcon: selectedIcon,
|
||||
unselectedIcon: unselectedIcon,
|
||||
page: PortForwardPage(
|
||||
key: ValueKey(params['id']),
|
||||
id: params['id'],
|
||||
isRDP: params['isRDP'],
|
||||
)));
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
tabController.onRemove = (_, id) => onRemoveId(id);
|
||||
|
||||
rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
|
||||
print(
|
||||
"call ${call.method} with args ${call.arguments} from window ${fromWindowId}");
|
||||
// for simplify, just replace connectionId
|
||||
if (call.method == "new_port_forward") {
|
||||
final args = jsonDecode(call.arguments);
|
||||
final id = args['id'];
|
||||
final isRDP = args['isRDP'];
|
||||
window_on_top(windowId());
|
||||
tabController.add(TabInfo(
|
||||
key: id,
|
||||
label: id,
|
||||
selectedIcon: selectedIcon,
|
||||
unselectedIcon: unselectedIcon,
|
||||
page: PortForwardPage(id: id, isRDP: isRDP)));
|
||||
} else if (call.method == "onDestroy") {
|
||||
tabController.state.value.tabs.forEach((tab) {
|
||||
print("executing onDestroy hook, closing ${tab.label}}");
|
||||
final tag = tab.label;
|
||||
ffi(tag).close().then((_) {
|
||||
Get.delete<FFI>(tag: tag);
|
||||
});
|
||||
});
|
||||
Get.back();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = isDarkTheme() ? TarBarTheme.dark() : TarBarTheme.light();
|
||||
return SubWindowDragToResizeArea(
|
||||
windowId: windowId(),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: MyTheme.color(context).border!)),
|
||||
child: Scaffold(
|
||||
backgroundColor: MyTheme.color(context).bg,
|
||||
body: DesktopTab(
|
||||
controller: tabController,
|
||||
theme: theme,
|
||||
isMainWindow: false,
|
||||
tail: AddButton(
|
||||
theme: theme,
|
||||
).paddingOnly(left: 10),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void onRemoveId(String id) {
|
||||
ffi("pf_$id").close();
|
||||
if (tabController.state.value.tabs.length == 0) {
|
||||
WindowController.fromWindowId(windowId()).close();
|
||||
}
|
||||
}
|
||||
|
||||
int windowId() {
|
||||
return widget.params["windowId"];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user