1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003 |
- import 'dart:async';
- import 'dart:io';
- import 'dart:convert';
- import 'package:auto_size_text/auto_size_text.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter_hbb/common.dart';
- import 'package:flutter_hbb/common/widgets/animated_rotation_widget.dart';
- import 'package:flutter_hbb/common/widgets/custom_password.dart';
- import 'package:flutter_hbb/consts.dart';
- import 'package:flutter_hbb/desktop/pages/connection_page.dart';
- import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
- import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
- import 'package:flutter_hbb/models/platform_model.dart';
- import 'package:flutter_hbb/models/server_model.dart';
- import 'package:flutter_hbb/models/state_model.dart';
- import 'package:flutter_hbb/plugin/ui_manager.dart';
- import 'package:flutter_hbb/utils/multi_window_manager.dart';
- import 'package:get/get.dart';
- import 'package:provider/provider.dart';
- import 'package:url_launcher/url_launcher.dart';
- import 'package:window_manager/window_manager.dart';
- import 'package:window_size/window_size.dart' as window_size;
- import '../widgets/button.dart';
- class DesktopHomePage extends StatefulWidget {
- const DesktopHomePage({Key? key}) : super(key: key);
- @override
- State<DesktopHomePage> createState() => _DesktopHomePageState();
- }
- const borderColor = Color(0xFF2F65BA);
- class _DesktopHomePageState extends State<DesktopHomePage>
- with AutomaticKeepAliveClientMixin, WidgetsBindingObserver {
- final _leftPaneScrollController = ScrollController();
- @override
- bool get wantKeepAlive => true;
- var systemError = '';
- StreamSubscription? _uniLinksSubscription;
- var svcStopped = false.obs;
- var watchIsCanScreenRecording = false;
- var watchIsProcessTrust = false;
- var watchIsInputMonitoring = false;
- var watchIsCanRecordAudio = false;
- Timer? _updateTimer;
- bool isCardClosed = false;
- final RxBool _editHover = false.obs;
- final RxBool _block = false.obs;
- final GlobalKey _childKey = GlobalKey();
- @override
- Widget build(BuildContext context) {
- super.build(context);
- final isIncomingOnly = bind.isIncomingOnly();
- return _buildBlock(
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- buildLeftPane(context),
- if (!isIncomingOnly) const VerticalDivider(width: 1),
- if (!isIncomingOnly) Expanded(child: buildRightPane(context)),
- ],
- ));
- }
- Widget _buildBlock({required Widget child}) {
- return buildRemoteBlock(
- block: _block, mask: true, use: canBeBlocked, child: child);
- }
- Widget buildLeftPane(BuildContext context) {
- final isIncomingOnly = bind.isIncomingOnly();
- final isOutgoingOnly = bind.isOutgoingOnly();
- final children = <Widget>[
- if (!isOutgoingOnly) buildPresetPasswordWarning(),
- if (bind.isCustomClient())
- Align(
- alignment: Alignment.center,
- child: loadPowered(context),
- ),
- Align(
- alignment: Alignment.center,
- child: loadLogo(),
- ),
- buildTip(context),
- if (!isOutgoingOnly) buildIDBoard(context),
- if (!isOutgoingOnly) buildPasswordBoard(context),
- FutureBuilder<Widget>(
- future: Future.value(
- Obx(() => buildHelpCards(stateGlobal.updateUrl.value))),
- builder: (_, data) {
- if (data.hasData) {
- if (isIncomingOnly) {
- if (isInHomePage()) {
- Future.delayed(Duration(milliseconds: 300), () {
- _updateWindowSize();
- });
- }
- }
- return data.data!;
- } else {
- return const Offstage();
- }
- },
- ),
- buildPluginEntry(),
- ];
- if (isIncomingOnly) {
- children.addAll([
- Divider(),
- OnlineStatusWidget(
- onSvcStatusChanged: () {
- if (isInHomePage()) {
- Future.delayed(Duration(milliseconds: 300), () {
- _updateWindowSize();
- });
- }
- },
- ).marginOnly(bottom: 6, right: 6)
- ]);
- }
- final textColor = Theme.of(context).textTheme.titleLarge?.color;
- return ChangeNotifierProvider.value(
- value: gFFI.serverModel,
- child: Container(
- width: isIncomingOnly ? 280.0 : 200.0,
- color: Theme.of(context).colorScheme.background,
- child: Stack(
- children: [
- SingleChildScrollView(
- controller: _leftPaneScrollController,
- child: Column(
- key: _childKey,
- children: children,
- ),
- ),
- if (isOutgoingOnly)
- Positioned(
- bottom: 6,
- left: 12,
- child: Align(
- alignment: Alignment.centerLeft,
- child: InkWell(
- child: Obx(
- () => Icon(
- Icons.settings,
- color: _editHover.value
- ? textColor
- : Colors.grey.withOpacity(0.5),
- size: 22,
- ),
- ),
- onTap: () => {
- if (DesktopSettingPage.tabKeys.isNotEmpty)
- {
- DesktopSettingPage.switch2page(
- DesktopSettingPage.tabKeys[0])
- }
- },
- onHover: (value) => _editHover.value = value,
- ),
- ),
- )
- ],
- ),
- ),
- );
- }
- buildRightPane(BuildContext context) {
- return Container(
- color: Theme.of(context).scaffoldBackgroundColor,
- child: ConnectionPage(),
- );
- }
- buildIDBoard(BuildContext context) {
- final model = gFFI.serverModel;
- return Container(
- margin: const EdgeInsets.only(left: 20, right: 11),
- height: 57,
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.baseline,
- textBaseline: TextBaseline.alphabetic,
- children: [
- Container(
- width: 2,
- decoration: const BoxDecoration(color: MyTheme.accent),
- ).marginOnly(top: 5),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(left: 7),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Container(
- height: 25,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- translate("ID"),
- style: TextStyle(
- fontSize: 14,
- color: Theme.of(context)
- .textTheme
- .titleLarge
- ?.color
- ?.withOpacity(0.5)),
- ).marginOnly(top: 5),
- buildPopupMenu(context)
- ],
- ),
- ),
- Flexible(
- child: GestureDetector(
- onDoubleTap: () {
- Clipboard.setData(
- ClipboardData(text: model.serverId.text));
- showToast(translate("Copied"));
- },
- child: TextFormField(
- controller: model.serverId,
- readOnly: true,
- decoration: InputDecoration(
- border: InputBorder.none,
- contentPadding: EdgeInsets.only(top: 10, bottom: 10),
- ),
- style: TextStyle(
- fontSize: 22,
- ),
- ).workaroundFreezeLinuxMint(),
- ),
- )
- ],
- ),
- ),
- ),
- ],
- ),
- );
- }
- Widget buildPopupMenu(BuildContext context) {
- final textColor = Theme.of(context).textTheme.titleLarge?.color;
- RxBool hover = false.obs;
- return InkWell(
- onTap: DesktopTabPage.onAddSetting,
- child: Tooltip(
- message: translate('Settings'),
- child: Obx(
- () => CircleAvatar(
- radius: 15,
- backgroundColor: hover.value
- ? Theme.of(context).scaffoldBackgroundColor
- : Theme.of(context).colorScheme.background,
- child: Icon(
- Icons.more_vert_outlined,
- size: 20,
- color: hover.value ? textColor : textColor?.withOpacity(0.5),
- ),
- ),
- ),
- ),
- onHover: (value) => hover.value = value,
- );
- }
- buildPasswordBoard(BuildContext context) {
- return ChangeNotifierProvider.value(
- value: gFFI.serverModel,
- child: Consumer<ServerModel>(
- builder: (context, model, child) {
- return buildPasswordBoard2(context, model);
- },
- ));
- }
- buildPasswordBoard2(BuildContext context, ServerModel model) {
- RxBool refreshHover = false.obs;
- RxBool editHover = false.obs;
- final textColor = Theme.of(context).textTheme.titleLarge?.color;
- final showOneTime = model.approveMode != 'click' &&
- model.verificationMethod != kUsePermanentPassword;
- return Container(
- margin: EdgeInsets.only(left: 20.0, right: 16, top: 13, bottom: 13),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.baseline,
- textBaseline: TextBaseline.alphabetic,
- children: [
- Container(
- width: 2,
- height: 52,
- decoration: BoxDecoration(color: MyTheme.accent),
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(left: 7),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- AutoSizeText(
- translate("One-time Password"),
- style: TextStyle(
- fontSize: 14, color: textColor?.withOpacity(0.5)),
- maxLines: 1,
- ),
- Row(
- children: [
- Expanded(
- child: GestureDetector(
- onDoubleTap: () {
- if (showOneTime) {
- Clipboard.setData(
- ClipboardData(text: model.serverPasswd.text));
- showToast(translate("Copied"));
- }
- },
- child: TextFormField(
- controller: model.serverPasswd,
- readOnly: true,
- decoration: InputDecoration(
- border: InputBorder.none,
- contentPadding:
- EdgeInsets.only(top: 14, bottom: 10),
- ),
- style: TextStyle(fontSize: 15),
- ).workaroundFreezeLinuxMint(),
- ),
- ),
- if (showOneTime)
- AnimatedRotationWidget(
- onPressed: () => bind.mainUpdateTemporaryPassword(),
- child: Tooltip(
- message: translate('Refresh Password'),
- child: Obx(() => RotatedBox(
- quarterTurns: 2,
- child: Icon(
- Icons.refresh,
- color: refreshHover.value
- ? textColor
- : Color(0xFFDDDDDD),
- size: 22,
- ))),
- ),
- onHover: (value) => refreshHover.value = value,
- ).marginOnly(right: 8, top: 4),
- if (!bind.isDisableSettings())
- InkWell(
- child: Tooltip(
- message: translate('Change Password'),
- child: Obx(
- () => Icon(
- Icons.edit,
- color: editHover.value
- ? textColor
- : Color(0xFFDDDDDD),
- size: 22,
- ).marginOnly(right: 8, top: 4),
- ),
- ),
- onTap: () => DesktopSettingPage.switch2page(
- SettingsTabKey.safety),
- onHover: (value) => editHover.value = value,
- ),
- ],
- ),
- ],
- ),
- ),
- ),
- ],
- ),
- );
- }
- buildTip(BuildContext context) {
- final isOutgoingOnly = bind.isOutgoingOnly();
- return Padding(
- padding:
- const EdgeInsets.only(left: 20.0, right: 16, top: 16.0, bottom: 5),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Column(
- children: [
- if (!isOutgoingOnly)
- Align(
- alignment: Alignment.centerLeft,
- child: Text(
- translate("Your Desktop"),
- style: Theme.of(context).textTheme.titleLarge,
- ),
- ),
- ],
- ),
- SizedBox(
- height: 10.0,
- ),
- if (!isOutgoingOnly)
- Text(
- translate("desk_tip"),
- overflow: TextOverflow.clip,
- style: Theme.of(context).textTheme.bodySmall,
- ),
- if (isOutgoingOnly)
- Text(
- translate("outgoing_only_desk_tip"),
- overflow: TextOverflow.clip,
- style: Theme.of(context).textTheme.bodySmall,
- ),
- ],
- ),
- );
- }
- Widget buildHelpCards(String updateUrl) {
- if (!bind.isCustomClient() &&
- updateUrl.isNotEmpty &&
- !isCardClosed &&
- bind.mainUriPrefixSync().contains('rustdesk')) {
- return buildInstallCard(
- "Status",
- "${translate("new-version-of-{${bind.mainGetAppNameSync()}}-tip")} (${bind.mainGetNewVersion()}).",
- "Click to download", () async {
- final Uri url = Uri.parse('https://rustdesk.com/download');
- await launchUrl(url);
- }, closeButton: true);
- }
- if (systemError.isNotEmpty) {
- return buildInstallCard("", systemError, "", () {});
- }
- if (isWindows && !bind.isDisableInstallation()) {
- if (!bind.mainIsInstalled()) {
- return buildInstallCard(
- "", bind.isOutgoingOnly() ? "" : "install_tip", "Install",
- () async {
- await rustDeskWinManager.closeAllSubWindows();
- bind.mainGotoInstall();
- });
- } else if (bind.mainIsInstalledLowerVersion()) {
- return buildInstallCard(
- "Status", "Your installation is lower version.", "Click to upgrade",
- () async {
- await rustDeskWinManager.closeAllSubWindows();
- bind.mainUpdateMe();
- });
- }
- } else if (isMacOS) {
- final isOutgoingOnly = bind.isOutgoingOnly();
- if (!(isOutgoingOnly || bind.mainIsCanScreenRecording(prompt: false))) {
- return buildInstallCard("Permissions", "config_screen", "Configure",
- () async {
- bind.mainIsCanScreenRecording(prompt: true);
- watchIsCanScreenRecording = true;
- }, help: 'Help', link: translate("doc_mac_permission"));
- } else if (!isOutgoingOnly && !bind.mainIsProcessTrusted(prompt: false)) {
- return buildInstallCard("Permissions", "config_acc", "Configure",
- () async {
- bind.mainIsProcessTrusted(prompt: true);
- watchIsProcessTrust = true;
- }, help: 'Help', link: translate("doc_mac_permission"));
- } else if (!bind.mainIsCanInputMonitoring(prompt: false)) {
- return buildInstallCard("Permissions", "config_input", "Configure",
- () async {
- bind.mainIsCanInputMonitoring(prompt: true);
- watchIsInputMonitoring = true;
- }, help: 'Help', link: translate("doc_mac_permission"));
- } else if (!isOutgoingOnly &&
- !svcStopped.value &&
- bind.mainIsInstalled() &&
- !bind.mainIsInstalledDaemon(prompt: false)) {
- return buildInstallCard("", "install_daemon_tip", "Install", () async {
- bind.mainIsInstalledDaemon(prompt: true);
- });
- }
- //// Disable microphone configuration for macOS. We will request the permission when needed.
- // else if ((await osxCanRecordAudio() !=
- // PermissionAuthorizeType.authorized)) {
- // return buildInstallCard("Permissions", "config_microphone", "Configure",
- // () async {
- // osxRequestAudio();
- // watchIsCanRecordAudio = true;
- // });
- // }
- } else if (isLinux) {
- if (bind.isOutgoingOnly()) {
- return Container();
- }
- final LinuxCards = <Widget>[];
- if (bind.isSelinuxEnforcing()) {
- // Check is SELinux enforcing, but show user a tip of is SELinux enabled for simple.
- final keyShowSelinuxHelpTip = "show-selinux-help-tip";
- if (bind.mainGetLocalOption(key: keyShowSelinuxHelpTip) != 'N') {
- LinuxCards.add(buildInstallCard(
- "Warning",
- "selinux_tip",
- "",
- () async {},
- marginTop: LinuxCards.isEmpty ? 20.0 : 5.0,
- help: 'Help',
- link:
- 'https://rustdesk.com/docs/en/client/linux/#permissions-issue',
- closeButton: true,
- closeOption: keyShowSelinuxHelpTip,
- ));
- }
- }
- if (bind.mainCurrentIsWayland()) {
- LinuxCards.add(buildInstallCard(
- "Warning", "wayland_experiment_tip", "", () async {},
- marginTop: LinuxCards.isEmpty ? 20.0 : 5.0,
- help: 'Help',
- link: 'https://rustdesk.com/docs/en/client/linux/#x11-required'));
- } else if (bind.mainIsLoginWayland()) {
- LinuxCards.add(buildInstallCard("Warning",
- "Login screen using Wayland is not supported", "", () async {},
- marginTop: LinuxCards.isEmpty ? 20.0 : 5.0,
- help: 'Help',
- link: 'https://rustdesk.com/docs/en/client/linux/#login-screen'));
- }
- if (LinuxCards.isNotEmpty) {
- return Column(
- children: LinuxCards,
- );
- }
- }
- if (bind.isIncomingOnly()) {
- return Align(
- alignment: Alignment.centerRight,
- child: OutlinedButton(
- onPressed: () {
- SystemNavigator.pop(); // Close the application
- // https://github.com/flutter/flutter/issues/66631
- if (isWindows) {
- exit(0);
- }
- },
- child: Text(translate('Quit')),
- ),
- ).marginAll(14);
- }
- return Container();
- }
- Widget buildInstallCard(String title, String content, String btnText,
- GestureTapCallback onPressed,
- {double marginTop = 20.0,
- String? help,
- String? link,
- bool? closeButton,
- String? closeOption}) {
- if (bind.mainGetBuildinOption(key: kOptionHideHelpCards) == 'Y' &&
- content != 'install_daemon_tip') {
- return const SizedBox();
- }
- void closeCard() async {
- if (closeOption != null) {
- await bind.mainSetLocalOption(key: closeOption, value: 'N');
- if (bind.mainGetLocalOption(key: closeOption) == 'N') {
- setState(() {
- isCardClosed = true;
- });
- }
- } else {
- setState(() {
- isCardClosed = true;
- });
- }
- }
- return Stack(
- children: [
- Container(
- margin: EdgeInsets.fromLTRB(
- 0, marginTop, 0, bind.isIncomingOnly() ? marginTop : 0),
- child: Container(
- decoration: BoxDecoration(
- gradient: LinearGradient(
- begin: Alignment.centerLeft,
- end: Alignment.centerRight,
- colors: [
- Color.fromARGB(255, 226, 66, 188),
- Color.fromARGB(255, 244, 114, 124),
- ],
- )),
- padding: EdgeInsets.all(20),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: (title.isNotEmpty
- ? <Widget>[
- Center(
- child: Text(
- translate(title),
- style: TextStyle(
- color: Colors.white,
- fontWeight: FontWeight.bold,
- fontSize: 15),
- ).marginOnly(bottom: 6)),
- ]
- : <Widget>[]) +
- <Widget>[
- if (content.isNotEmpty)
- Text(
- translate(content),
- style: TextStyle(
- height: 1.5,
- color: Colors.white,
- fontWeight: FontWeight.normal,
- fontSize: 13),
- ).marginOnly(bottom: 20)
- ] +
- (btnText.isNotEmpty
- ? <Widget>[
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- FixedWidthButton(
- width: 150,
- padding: 8,
- isOutline: true,
- text: translate(btnText),
- textColor: Colors.white,
- borderColor: Colors.white,
- textSize: 20,
- radius: 10,
- onTap: onPressed,
- )
- ])
- ]
- : <Widget>[]) +
- (help != null
- ? <Widget>[
- Center(
- child: InkWell(
- onTap: () async =>
- await launchUrl(Uri.parse(link!)),
- child: Text(
- translate(help),
- style: TextStyle(
- decoration:
- TextDecoration.underline,
- color: Colors.white,
- fontSize: 12),
- )).marginOnly(top: 6)),
- ]
- : <Widget>[]))),
- ),
- if (closeButton != null && closeButton == true)
- Positioned(
- top: 18,
- right: 0,
- child: IconButton(
- icon: Icon(
- Icons.close,
- color: Colors.white,
- size: 20,
- ),
- onPressed: closeCard,
- ),
- ),
- ],
- );
- }
- @override
- void initState() {
- super.initState();
- _updateTimer = periodic_immediate(const Duration(seconds: 1), () async {
- await gFFI.serverModel.fetchID();
- final error = await bind.mainGetError();
- if (systemError != error) {
- systemError = error;
- setState(() {});
- }
- final v = await mainGetBoolOption(kOptionStopService);
- if (v != svcStopped.value) {
- svcStopped.value = v;
- setState(() {});
- }
- if (watchIsCanScreenRecording) {
- if (bind.mainIsCanScreenRecording(prompt: false)) {
- watchIsCanScreenRecording = false;
- setState(() {});
- }
- }
- if (watchIsProcessTrust) {
- if (bind.mainIsProcessTrusted(prompt: false)) {
- watchIsProcessTrust = false;
- setState(() {});
- }
- }
- if (watchIsInputMonitoring) {
- if (bind.mainIsCanInputMonitoring(prompt: false)) {
- watchIsInputMonitoring = false;
- // Do not notify for now.
- // Monitoring may not take effect until the process is restarted.
- // rustDeskWinManager.call(
- // WindowType.RemoteDesktop, kWindowDisableGrabKeyboard, '');
- setState(() {});
- }
- }
- if (watchIsCanRecordAudio) {
- if (isMacOS) {
- Future.microtask(() async {
- if ((await osxCanRecordAudio() ==
- PermissionAuthorizeType.authorized)) {
- watchIsCanRecordAudio = false;
- setState(() {});
- }
- });
- } else {
- watchIsCanRecordAudio = false;
- setState(() {});
- }
- }
- });
- Get.put<RxBool>(svcStopped, tag: 'stop-service');
- rustDeskWinManager.registerActiveWindowListener(onActiveWindowChanged);
- screenToMap(window_size.Screen screen) => {
- 'frame': {
- 'l': screen.frame.left,
- 't': screen.frame.top,
- 'r': screen.frame.right,
- 'b': screen.frame.bottom,
- },
- 'visibleFrame': {
- 'l': screen.visibleFrame.left,
- 't': screen.visibleFrame.top,
- 'r': screen.visibleFrame.right,
- 'b': screen.visibleFrame.bottom,
- },
- 'scaleFactor': screen.scaleFactor,
- };
- rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
- debugPrint(
- "[Main] call ${call.method} with args ${call.arguments} from window $fromWindowId");
- if (call.method == kWindowMainWindowOnTop) {
- windowOnTop(null);
- } else if (call.method == kWindowGetWindowInfo) {
- final screen = (await window_size.getWindowInfo()).screen;
- if (screen == null) {
- return '';
- } else {
- return jsonEncode(screenToMap(screen));
- }
- } else if (call.method == kWindowGetScreenList) {
- return jsonEncode(
- (await window_size.getScreenList()).map(screenToMap).toList());
- } else if (call.method == kWindowActionRebuild) {
- reloadCurrentWindow();
- } else if (call.method == kWindowEventShow) {
- await rustDeskWinManager.registerActiveWindow(call.arguments["id"]);
- } else if (call.method == kWindowEventHide) {
- await rustDeskWinManager.unregisterActiveWindow(call.arguments['id']);
- } else if (call.method == kWindowConnect) {
- await connectMainDesktop(
- call.arguments['id'],
- isFileTransfer: call.arguments['isFileTransfer'],
- isTcpTunneling: call.arguments['isTcpTunneling'],
- isRDP: call.arguments['isRDP'],
- password: call.arguments['password'],
- forceRelay: call.arguments['forceRelay'],
- connToken: call.arguments['connToken'],
- );
- } else if (call.method == kWindowEventMoveTabToNewWindow) {
- final args = call.arguments.split(',');
- int? windowId;
- try {
- windowId = int.parse(args[0]);
- } catch (e) {
- debugPrint("Failed to parse window id '${call.arguments}': $e");
- }
- if (windowId != null) {
- await rustDeskWinManager.moveTabToNewWindow(
- windowId, args[1], args[2]);
- }
- } else if (call.method == kWindowEventOpenMonitorSession) {
- final args = jsonDecode(call.arguments);
- final windowId = args['window_id'] as int;
- final peerId = args['peer_id'] as String;
- final display = args['display'] as int;
- final displayCount = args['display_count'] as int;
- final screenRect = parseParamScreenRect(args);
- await rustDeskWinManager.openMonitorSession(
- windowId, peerId, display, displayCount, screenRect);
- } else if (call.method == kWindowEventRemoteWindowCoords) {
- final windowId = int.tryParse(call.arguments);
- if (windowId != null) {
- return jsonEncode(
- await rustDeskWinManager.getOtherRemoteWindowCoords(windowId));
- }
- }
- });
- _uniLinksSubscription = listenUniLinks();
- if (bind.isIncomingOnly()) {
- WidgetsBinding.instance.addPostFrameCallback((_) {
- _updateWindowSize();
- });
- }
- WidgetsBinding.instance.addObserver(this);
- }
- _updateWindowSize() {
- RenderObject? renderObject = _childKey.currentContext?.findRenderObject();
- if (renderObject == null) {
- return;
- }
- if (renderObject is RenderBox) {
- final size = renderObject.size;
- if (size != imcomingOnlyHomeSize) {
- imcomingOnlyHomeSize = size;
- windowManager.setSize(getIncomingOnlyHomeSize());
- }
- }
- }
- @override
- void dispose() {
- _uniLinksSubscription?.cancel();
- Get.delete<RxBool>(tag: 'stop-service');
- _updateTimer?.cancel();
- WidgetsBinding.instance.removeObserver(this);
- super.dispose();
- }
- @override
- void didChangeAppLifecycleState(AppLifecycleState state) {
- super.didChangeAppLifecycleState(state);
- if (state == AppLifecycleState.resumed) {
- shouldBeBlocked(_block, canBeBlocked);
- }
- }
- Widget buildPluginEntry() {
- final entries = PluginUiManager.instance.entries.entries;
- return Offstage(
- offstage: entries.isEmpty,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- ...entries.map((entry) {
- return entry.value;
- })
- ],
- ),
- );
- }
- }
- void setPasswordDialog({VoidCallback? notEmptyCallback}) async {
- final pw = await bind.mainGetPermanentPassword();
- final p0 = TextEditingController(text: pw);
- final p1 = TextEditingController(text: pw);
- var errMsg0 = "";
- var errMsg1 = "";
- final RxString rxPass = pw.trim().obs;
- final rules = [
- DigitValidationRule(),
- UppercaseValidationRule(),
- LowercaseValidationRule(),
- // SpecialCharacterValidationRule(),
- MinCharactersValidationRule(8),
- ];
- final maxLength = bind.mainMaxEncryptLen();
- gFFI.dialogManager.show((setState, close, context) {
- submit() {
- setState(() {
- errMsg0 = "";
- errMsg1 = "";
- });
- final pass = p0.text.trim();
- if (pass.isNotEmpty) {
- final Iterable violations = rules.where((r) => !r.validate(pass));
- if (violations.isNotEmpty) {
- setState(() {
- errMsg0 =
- '${translate('Prompt')}: ${violations.map((r) => r.name).join(', ')}';
- });
- return;
- }
- }
- if (p1.text.trim() != pass) {
- setState(() {
- errMsg1 =
- '${translate('Prompt')}: ${translate("The confirmation is not identical.")}';
- });
- return;
- }
- bind.mainSetPermanentPassword(password: pass);
- if (pass.isNotEmpty) {
- notEmptyCallback?.call();
- }
- close();
- }
- return CustomAlertDialog(
- title: Text(translate("Set Password")),
- content: ConstrainedBox(
- constraints: const BoxConstraints(minWidth: 500),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const SizedBox(
- height: 8.0,
- ),
- Row(
- children: [
- Expanded(
- child: TextField(
- obscureText: true,
- decoration: InputDecoration(
- labelText: translate('Password'),
- errorText: errMsg0.isNotEmpty ? errMsg0 : null),
- controller: p0,
- autofocus: true,
- onChanged: (value) {
- rxPass.value = value.trim();
- setState(() {
- errMsg0 = '';
- });
- },
- maxLength: maxLength,
- ).workaroundFreezeLinuxMint(),
- ),
- ],
- ),
- Row(
- children: [
- Expanded(child: PasswordStrengthIndicator(password: rxPass)),
- ],
- ).marginSymmetric(vertical: 8),
- const SizedBox(
- height: 8.0,
- ),
- Row(
- children: [
- Expanded(
- child: TextField(
- obscureText: true,
- decoration: InputDecoration(
- labelText: translate('Confirmation'),
- errorText: errMsg1.isNotEmpty ? errMsg1 : null),
- controller: p1,
- onChanged: (value) {
- setState(() {
- errMsg1 = '';
- });
- },
- maxLength: maxLength,
- ).workaroundFreezeLinuxMint(),
- ),
- ],
- ),
- const SizedBox(
- height: 8.0,
- ),
- Obx(() => Wrap(
- runSpacing: 8,
- spacing: 4,
- children: rules.map((e) {
- var checked = e.validate(rxPass.value.trim());
- return Chip(
- label: Text(
- e.name,
- style: TextStyle(
- color: checked
- ? const Color(0xFF0A9471)
- : Color.fromARGB(255, 198, 86, 157)),
- ),
- backgroundColor: checked
- ? const Color(0xFFD0F7ED)
- : Color.fromARGB(255, 247, 205, 232));
- }).toList(),
- ))
- ],
- ),
- ),
- actions: [
- dialogButton("Cancel", onPressed: close, isOutline: true),
- dialogButton("OK", onPressed: submit),
- ],
- onSubmit: submit,
- onCancel: close,
- );
- });
- }
|