Merge pull request #979 from Kingtous/flutter_desktop
feat: main menu implementation for flutter desktop
This commit is contained in:
commit
fc06762a94
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
@ -44,15 +45,23 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Provider.of<FfiModel>(context);
|
Provider.of<FfiModel>(context);
|
||||||
if (_idController.text.isEmpty) _idController.text = gFFI.getId();
|
if (_idController.text.isEmpty) _idController.text = gFFI.getId();
|
||||||
return SingleChildScrollView(
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: MyTheme.grayBg
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
getUpdateUI(),
|
getUpdateUI(),
|
||||||
getSearchBarUI(),
|
Row(
|
||||||
|
children: [
|
||||||
|
getSearchBarUI(),
|
||||||
|
],
|
||||||
|
).marginOnly(top: 16.0, left: 16.0),
|
||||||
SizedBox(height: 12),
|
SizedBox(height: 12),
|
||||||
|
Divider(thickness: 1,),
|
||||||
getPeers(),
|
getPeers(),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
@ -106,104 +115,102 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
/// UI for the search bar.
|
/// UI for the search bar.
|
||||||
/// Search for a peer and connect to it if the id exists.
|
/// Search for a peer and connect to it if the id exists.
|
||||||
Widget getSearchBarUI() {
|
Widget getSearchBarUI() {
|
||||||
var w = Padding(
|
var w = Container(
|
||||||
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 16.0),
|
width: 500,
|
||||||
child: Container(
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 24),
|
||||||
child: Padding(
|
decoration: BoxDecoration(
|
||||||
padding: const EdgeInsets.only(top: 16, bottom: 16),
|
color: MyTheme.white,
|
||||||
child: Ink(
|
borderRadius: const BorderRadius.all(Radius.circular(13)),
|
||||||
decoration: BoxDecoration(
|
),
|
||||||
color: MyTheme.white,
|
child: Ink(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(13)),
|
child: Column(
|
||||||
),
|
children: [
|
||||||
child: Column(
|
Row(
|
||||||
children: [
|
children: <Widget>[
|
||||||
Row(
|
Expanded(
|
||||||
children: <Widget>[
|
child: Container(
|
||||||
Expanded(
|
child: TextField(
|
||||||
child: Container(
|
autocorrect: false,
|
||||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
enableSuggestions: false,
|
||||||
child: TextField(
|
keyboardType: TextInputType.visiblePassword,
|
||||||
autocorrect: false,
|
// keyboardType: TextInputType.number,
|
||||||
enableSuggestions: false,
|
style: TextStyle(
|
||||||
keyboardType: TextInputType.visiblePassword,
|
fontFamily: 'WorkSans',
|
||||||
// keyboardType: TextInputType.number,
|
fontWeight: FontWeight.bold,
|
||||||
style: TextStyle(
|
fontSize: 30,
|
||||||
fontFamily: 'WorkSans',
|
// color: MyTheme.idColor,
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
fontSize: 30,
|
decoration: InputDecoration(
|
||||||
// color: MyTheme.idColor,
|
labelText: translate('Control Remote Desktop'),
|
||||||
),
|
// hintText: 'Enter your remote ID',
|
||||||
decoration: InputDecoration(
|
// border: InputBorder.,
|
||||||
labelText: translate('Control Remote Desktop'),
|
border: OutlineInputBorder(
|
||||||
// hintText: 'Enter your remote ID',
|
borderRadius: BorderRadius.zero),
|
||||||
// border: InputBorder.,
|
helperStyle: TextStyle(
|
||||||
border: OutlineInputBorder(
|
fontWeight: FontWeight.bold,
|
||||||
borderRadius: BorderRadius.zero),
|
fontSize: 16,
|
||||||
helperStyle: TextStyle(
|
color: MyTheme.dark,
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
fontSize: 16,
|
labelStyle: TextStyle(
|
||||||
color: MyTheme.dark,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
fontSize: 26,
|
||||||
labelStyle: TextStyle(
|
letterSpacing: 0.2,
|
||||||
fontWeight: FontWeight.w600,
|
color: MyTheme.dark,
|
||||||
fontSize: 26,
|
|
||||||
letterSpacing: 0.2,
|
|
||||||
color: MyTheme.dark,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
controller: _idController,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
controller: _idController,
|
||||||
|
onSubmitted: (s) {
|
||||||
|
onConnect();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 16.0, horizontal: 16.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
OutlinedButton(
|
|
||||||
onPressed: () {
|
|
||||||
onConnect(isFileTransfer: true);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 8.0, horizontal: 8.0),
|
|
||||||
child: Text(
|
|
||||||
translate(
|
|
||||||
"Transfer File",
|
|
||||||
),
|
|
||||||
style: TextStyle(color: MyTheme.dark),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 30,
|
|
||||||
),
|
|
||||||
OutlinedButton(
|
|
||||||
onPressed: onConnect,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 8.0, horizontal: 16.0),
|
|
||||||
child: Text(
|
|
||||||
translate(
|
|
||||||
"Connection",
|
|
||||||
),
|
|
||||||
style: TextStyle(color: MyTheme.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.blueAccent,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 16.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () {
|
||||||
|
onConnect(isFileTransfer: true);
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8.0, horizontal: 8.0),
|
||||||
|
child: Text(
|
||||||
|
translate(
|
||||||
|
"Transfer File",
|
||||||
|
),
|
||||||
|
style: TextStyle(color: MyTheme.dark),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 30,
|
||||||
|
),
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: onConnect,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8.0, horizontal: 16.0),
|
||||||
|
child: Text(
|
||||||
|
translate(
|
||||||
|
"Connection",
|
||||||
|
),
|
||||||
|
style: TextStyle(color: MyTheme.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.blueAccent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart' hide MenuItem;
|
import 'package:flutter/material.dart' hide MenuItem;
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/connection_page.dart';
|
import 'package:flutter_hbb/desktop/pages/connection_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/widgets/titlebar_widget.dart';
|
import 'package:flutter_hbb/desktop/widgets/titlebar_widget.dart';
|
||||||
import 'package:flutter_hbb/models/model.dart';
|
import 'package:flutter_hbb/models/model.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tray_manager/tray_manager.dart';
|
import 'package:tray_manager/tray_manager.dart';
|
||||||
|
|
||||||
@ -42,9 +44,6 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener {
|
|||||||
child: buildServerInfo(context),
|
child: buildServerInfo(context),
|
||||||
flex: 1,
|
flex: 1,
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
width: 16.0,
|
|
||||||
),
|
|
||||||
Flexible(
|
Flexible(
|
||||||
child: buildServerBoard(context),
|
child: buildServerBoard(context),
|
||||||
flex: 4,
|
flex: 4,
|
||||||
@ -76,12 +75,8 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener {
|
|||||||
|
|
||||||
buildServerBoard(BuildContext context) {
|
buildServerBoard(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
// buildControlPanel(context),
|
Expanded(child: ConnectionPage()),
|
||||||
// buildRecentSession(context),
|
|
||||||
Expanded(child: ConnectionPage())
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -105,9 +100,35 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Row(
|
||||||
translate("ID"),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
|
children: [
|
||||||
|
Text(
|
||||||
|
translate("ID"),
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
PopupMenuButton(
|
||||||
|
padding: EdgeInsets.all(4.0),
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
genEnablePopupMenuItem(translate("Enable Keyboard/Mouse"), 'enable-keyboard',),
|
||||||
|
genEnablePopupMenuItem(translate("Enable Clipboard"), 'enable-clipboard',),
|
||||||
|
genEnablePopupMenuItem(translate("Enable File Transfer"), 'enable-file-transfer',),
|
||||||
|
genEnablePopupMenuItem(translate("Enable TCP Tunneling"), 'enable-tunnel',),
|
||||||
|
genAudioInputPopupMenuItem(),
|
||||||
|
// TODO: Audio Input
|
||||||
|
PopupMenuItem(child: Text(translate("ID/Relay Server")), value: 'custom-server',),
|
||||||
|
PopupMenuItem(child: Text(translate("IP Whitelisting")), value: 'whitelist',),
|
||||||
|
PopupMenuItem(child: Text(translate("Socks5 Proxy")), value: 'Socks5 Proxy',),
|
||||||
|
// sep
|
||||||
|
genEnablePopupMenuItem(translate("Enable Service"), 'stop-service',),
|
||||||
|
// TODO: direct server
|
||||||
|
genEnablePopupMenuItem(translate("Always connected via relay"),'allow-always-relay',),
|
||||||
|
genEnablePopupMenuItem(translate("Start ID/relay service"),'stop-rendezvous-service',),
|
||||||
|
PopupMenuItem(child: Text(translate("Change ID")), value: 'change-id',),
|
||||||
|
genEnablePopupMenuItem(translate("Dark Theme"), 'allow-darktheme',),
|
||||||
|
PopupMenuItem(child: Text(translate("About")), value: 'about',),
|
||||||
|
], onSelected: onSelectMenu,)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: model.serverId,
|
controller: model.serverId,
|
||||||
@ -194,7 +215,9 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener {
|
|||||||
children: [
|
children: [
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: TextEditingController(),
|
controller: TextEditingController(),
|
||||||
inputFormatters: [],
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.allow(RegExp(r"[0-9]"))
|
||||||
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
@ -232,4 +255,152 @@ class _DesktopHomePageState extends State<DesktopHomePage> with TrayListener {
|
|||||||
trayManager.removeListener(this);
|
trayManager.removeListener(this);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onSelectMenu(String value) {
|
||||||
|
if (value.startsWith('enable-')) {
|
||||||
|
final option = gFFI.getOption(value);
|
||||||
|
gFFI.setOption(value, option == "N" ? "" : "N");
|
||||||
|
} else if (value.startsWith('allow-')) {
|
||||||
|
final option = gFFI.getOption(value);
|
||||||
|
gFFI.setOption(value, option == "Y" ? "" : "Y");
|
||||||
|
} else if (value == "stop-service") {
|
||||||
|
final option = gFFI.getOption(value);
|
||||||
|
gFFI.setOption(value, option == "Y" ? "" : "Y");
|
||||||
|
} else if (value == "change-id") {
|
||||||
|
changeId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupMenuItem<String> genEnablePopupMenuItem(String label, String value) {
|
||||||
|
final isEnable =
|
||||||
|
label.startsWith('enable-') ? gFFI.getOption(value) != "N" : gFFI.getOption(value) != "Y";
|
||||||
|
return PopupMenuItem(child: Row(
|
||||||
|
children: [
|
||||||
|
Offstage(offstage: !isEnable, child: Icon(Icons.check)),
|
||||||
|
Text(label, style: genTextStyle(isEnable),),
|
||||||
|
],
|
||||||
|
), value: value,);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextStyle genTextStyle(bool isPositive) {
|
||||||
|
return isPositive ? TextStyle() : TextStyle(
|
||||||
|
color: Colors.redAccent,
|
||||||
|
decoration: TextDecoration.lineThrough
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupMenuItem<String> genAudioInputPopupMenuItem() {
|
||||||
|
final _enabledInput = gFFI.getOption('enable-audio');
|
||||||
|
var defaultInput = gFFI.getDefaultAudioInput().obs;
|
||||||
|
var enabled = (_enabledInput != "N").obs;
|
||||||
|
return PopupMenuItem(child: FutureBuilder<List<String>>(
|
||||||
|
future: gFFI.getAudioInputs(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
final inputs = snapshot.data!;
|
||||||
|
if (Platform.isWindows) {
|
||||||
|
inputs.insert(0, translate("System Sound"));
|
||||||
|
}
|
||||||
|
var inputList = inputs.map((e) => PopupMenuItem(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Obx(()=> Offstage(offstage: defaultInput.value != e, child: Icon(Icons.check))),
|
||||||
|
Expanded(child: Tooltip(
|
||||||
|
message: e,
|
||||||
|
child: Text("$e",maxLines: 1, overflow: TextOverflow.ellipsis,))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
value: e,
|
||||||
|
)).toList();
|
||||||
|
inputList.insert(0, PopupMenuItem(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Obx(()=> Offstage(offstage: enabled.value, child: Icon(Icons.check))),
|
||||||
|
Expanded(child: Text(translate("Mute"))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
value: "Mute",
|
||||||
|
));
|
||||||
|
return PopupMenuButton<String>(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(translate("Audio Input"))),
|
||||||
|
itemBuilder: (context) => inputList,
|
||||||
|
onSelected: (dev) {
|
||||||
|
if (dev == "Mute") {
|
||||||
|
gFFI.setOption('enable-audio', _enabledInput == 'N' ? '': 'N');
|
||||||
|
enabled.value = gFFI.getOption('enable-audio') != 'N';
|
||||||
|
} else if (dev != gFFI.getDefaultAudioInput()) {
|
||||||
|
gFFI.setDefaultAudioInput(dev);
|
||||||
|
defaultInput.value = dev;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Text("...");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
), value: 'audio-input',);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// change local ID
|
||||||
|
void changeId() {
|
||||||
|
var newId = "";
|
||||||
|
var msg = "";
|
||||||
|
var isInProgress = false;
|
||||||
|
DialogManager.show( (setState, close) {
|
||||||
|
return CustomAlertDialog(
|
||||||
|
title: Text(translate("Change ID")),
|
||||||
|
content: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(translate("id_change_tip")),
|
||||||
|
Offstage(
|
||||||
|
offstage: msg.isEmpty,
|
||||||
|
child: Text(msg, style: TextStyle(color: Colors.grey),)).marginOnly(bottom: 4.0),
|
||||||
|
TextField(
|
||||||
|
onChanged: (s) {
|
||||||
|
newId = s;
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder()
|
||||||
|
),
|
||||||
|
inputFormatters: [
|
||||||
|
LengthLimitingTextInputFormatter(16),
|
||||||
|
// FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true)
|
||||||
|
],
|
||||||
|
maxLength: 16,
|
||||||
|
),
|
||||||
|
SizedBox(height: 4.0,),
|
||||||
|
Offstage(
|
||||||
|
offstage: !isInProgress,
|
||||||
|
child: LinearProgressIndicator())
|
||||||
|
],
|
||||||
|
), actions: [
|
||||||
|
TextButton(onPressed: (){
|
||||||
|
close();
|
||||||
|
}, child: Text("取消")),
|
||||||
|
TextButton(onPressed: () async {
|
||||||
|
setState(() {
|
||||||
|
msg = "";
|
||||||
|
isInProgress = true;
|
||||||
|
gFFI.bind.mainChangeId(newId: newId);
|
||||||
|
});
|
||||||
|
|
||||||
|
var status = await gFFI.bind.mainGetAsyncStatus();
|
||||||
|
while (status == " "){
|
||||||
|
await Future.delayed(Duration(milliseconds: 100));
|
||||||
|
status = await gFFI.bind.mainGetAsyncStatus();
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
isInProgress = false;
|
||||||
|
msg = translate(status);
|
||||||
|
});
|
||||||
|
|
||||||
|
}, child: Text("确定")),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
@ -990,6 +991,17 @@ class FFI {
|
|||||||
ffiModel.platformFFI.setByName(name, value);
|
ffiModel.platformFFI.setByName(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getOption(String name) {
|
||||||
|
return ffiModel.platformFFI.getByName("option", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOption(String name, String value) {
|
||||||
|
Map<String, String> res = Map()
|
||||||
|
..["name"] = name
|
||||||
|
..["value"] = value;
|
||||||
|
return ffiModel.platformFFI.setByName('option', jsonEncode(res));
|
||||||
|
}
|
||||||
|
|
||||||
RustdeskImpl get bind => ffiModel.platformFFI.ffiBind;
|
RustdeskImpl get bind => ffiModel.platformFFI.ffiBind;
|
||||||
|
|
||||||
handleMouse(Map<String, dynamic> evt) {
|
handleMouse(Map<String, dynamic> evt) {
|
||||||
@ -1062,6 +1074,22 @@ class FFI {
|
|||||||
Future<bool> invokeMethod(String method, [dynamic arguments]) async {
|
Future<bool> invokeMethod(String method, [dynamic arguments]) async {
|
||||||
return await ffiModel.platformFFI.invokeMethod(method, arguments);
|
return await ffiModel.platformFFI.invokeMethod(method, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<String>> getAudioInputs() async {
|
||||||
|
return await bind.mainGetSoundInputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDefaultAudioInput() {
|
||||||
|
final input = getOption('audio-input');
|
||||||
|
if (input.isEmpty && Platform.isWindows) {
|
||||||
|
return "System Sound";
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDefaultAudioInput(String input){
|
||||||
|
setOption('audio-input', input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Peer {
|
class Peer {
|
||||||
|
@ -187,8 +187,8 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: c7d97cb6615f2def34f8bad4def01af9e0077beb
|
ref: "7b72918710921f5fe79eae2dbaa411a66f5dfb45"
|
||||||
resolved-ref: c7d97cb6615f2def34f8bad4def01af9e0077beb
|
resolved-ref: "7b72918710921f5fe79eae2dbaa411a66f5dfb45"
|
||||||
url: "https://github.com/Kingtous/rustdesk_desktop_multi_window"
|
url: "https://github.com/Kingtous/rustdesk_desktop_multi_window"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
|
@ -19,6 +19,7 @@ use crate::flutter::connection_manager::{self, get_clients_length, get_clients_s
|
|||||||
use crate::flutter::{self, Session, SESSIONS};
|
use crate::flutter::{self, Session, SESSIONS};
|
||||||
use crate::start_server;
|
use crate::start_server;
|
||||||
use crate::ui_interface;
|
use crate::ui_interface;
|
||||||
|
use crate::ui_interface::{change_id, get_async_job_status, get_sound_inputs, is_ok_change_id};
|
||||||
|
|
||||||
fn initialize(app_dir: &str) {
|
fn initialize(app_dir: &str) {
|
||||||
*config::APP_DIR.write().unwrap() = app_dir.to_owned();
|
*config::APP_DIR.write().unwrap() = app_dir.to_owned();
|
||||||
@ -378,6 +379,18 @@ pub fn session_resume_job(id: String, act_id: i32, is_remote: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn main_get_sound_inputs() -> Vec<String> {
|
||||||
|
get_sound_inputs()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main_change_id(new_id: String) {
|
||||||
|
change_id(new_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main_get_async_status() -> String {
|
||||||
|
get_async_job_status()
|
||||||
|
}
|
||||||
|
|
||||||
/// FFI for **get** commands which are idempotent.
|
/// FFI for **get** commands which are idempotent.
|
||||||
/// Return result in c string.
|
/// Return result in c string.
|
||||||
///
|
///
|
||||||
|
Loading…
x
Reference in New Issue
Block a user