123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- import 'dart:async';
- import 'dart:convert';
- import 'package:flutter/material.dart';
- import 'package:flutter_hbb/consts.dart';
- import 'package:flutter_hbb/main.dart';
- import 'package:flutter_hbb/mobile/pages/settings_page.dart';
- import 'package:flutter_hbb/models/chat_model.dart';
- import 'package:flutter_hbb/models/platform_model.dart';
- import 'package:get/get.dart';
- import 'package:wakelock_plus/wakelock_plus.dart';
- import 'package:window_manager/window_manager.dart';
- import '../common.dart';
- import '../common/formatter/id_formatter.dart';
- import '../desktop/pages/server_page.dart' as desktop;
- import '../desktop/widgets/tabbar_widget.dart';
- import '../mobile/pages/server_page.dart';
- import 'model.dart';
- const kLoginDialogTag = "LOGIN";
- const kUseTemporaryPassword = "use-temporary-password";
- const kUsePermanentPassword = "use-permanent-password";
- const kUseBothPasswords = "use-both-passwords";
- class ServerModel with ChangeNotifier {
- bool _isStart = false; // Android MainService status
- bool _mediaOk = false;
- bool _inputOk = false;
- bool _audioOk = false;
- bool _fileOk = false;
- bool _clipboardOk = false;
- bool _showElevation = false;
- bool hideCm = false;
- int _connectStatus = 0; // Rendezvous Server status
- String _verificationMethod = "";
- String _temporaryPasswordLength = "";
- String _approveMode = "";
- int _zeroClientLengthCounter = 0;
- late String _emptyIdShow;
- late final IDTextEditingController _serverId;
- final _serverPasswd =
- TextEditingController(text: translate("Generating ..."));
- final tabController = DesktopTabController(tabType: DesktopTabType.cm);
- final List<Client> _clients = [];
- Timer? cmHiddenTimer;
- bool get isStart => _isStart;
- bool get mediaOk => _mediaOk;
- bool get inputOk => _inputOk;
- bool get audioOk => _audioOk;
- bool get fileOk => _fileOk;
- bool get clipboardOk => _clipboardOk;
- bool get showElevation => _showElevation;
- int get connectStatus => _connectStatus;
- String get verificationMethod {
- final index = [
- kUseTemporaryPassword,
- kUsePermanentPassword,
- kUseBothPasswords
- ].indexOf(_verificationMethod);
- if (index < 0) {
- return kUseBothPasswords;
- }
- return _verificationMethod;
- }
- String get approveMode => _approveMode;
- setVerificationMethod(String method) async {
- await bind.mainSetOption(key: kOptionVerificationMethod, value: method);
- /*
- if (method != kUsePermanentPassword) {
- await bind.mainSetOption(
- key: 'allow-hide-cm', value: bool2option('allow-hide-cm', false));
- }
- */
- }
- String get temporaryPasswordLength {
- final lengthIndex = ["6", "8", "10"].indexOf(_temporaryPasswordLength);
- if (lengthIndex < 0) {
- return "6";
- }
- return _temporaryPasswordLength;
- }
- setTemporaryPasswordLength(String length) async {
- await bind.mainSetOption(key: "temporary-password-length", value: length);
- }
- setApproveMode(String mode) async {
- await bind.mainSetOption(key: kOptionApproveMode, value: mode);
- /*
- if (mode != 'password') {
- await bind.mainSetOption(
- key: 'allow-hide-cm', value: bool2option('allow-hide-cm', false));
- }
- */
- }
- TextEditingController get serverId => _serverId;
- TextEditingController get serverPasswd => _serverPasswd;
- List<Client> get clients => _clients;
- final controller = ScrollController();
- WeakReference<FFI> parent;
- ServerModel(this.parent) {
- _emptyIdShow = translate("Generating ...");
- _serverId = IDTextEditingController(text: _emptyIdShow);
- /*
- // initital _hideCm at startup
- final verificationMethod =
- bind.mainGetOptionSync(key: kOptionVerificationMethod);
- final approveMode = bind.mainGetOptionSync(key: kOptionApproveMode);
- _hideCm = option2bool(
- 'allow-hide-cm', bind.mainGetOptionSync(key: 'allow-hide-cm'));
- if (!(approveMode == 'password' &&
- verificationMethod == kUsePermanentPassword)) {
- _hideCm = false;
- }
- */
- timerCallback() async {
- final connectionStatus =
- jsonDecode(await bind.mainGetConnectStatus()) as Map<String, dynamic>;
- final statusNum = connectionStatus['status_num'] as int;
- if (statusNum != _connectStatus) {
- _connectStatus = statusNum;
- notifyListeners();
- }
- if (desktopType == DesktopType.cm) {
- final res = await bind.cmCheckClientsLength(length: _clients.length);
- if (res != null) {
- debugPrint("clients not match!");
- updateClientState(res);
- } else {
- if (_clients.isEmpty) {
- hideCmWindow();
- if (_zeroClientLengthCounter++ == 12) {
- // 6 second
- windowManager.close();
- }
- } else {
- _zeroClientLengthCounter = 0;
- if (!hideCm) showCmWindow();
- }
- }
- }
- updatePasswordModel();
- }
- if (!isTest) {
- Future.delayed(Duration.zero, () async {
- if (await bind.optionSynced()) {
- await timerCallback();
- }
- });
- Timer.periodic(Duration(milliseconds: 500), (timer) async {
- await timerCallback();
- });
- }
- // Initial keyboard status is off on mobile
- if (isMobile) {
- bind.mainSetOption(key: kOptionEnableKeyboard, value: 'N');
- }
- }
- /// 1. check android permission
- /// 2. check config
- /// audio true by default (if permission on) (false default < Android 10)
- /// file true by default (if permission on)
- checkAndroidPermission() async {
- // audio
- if (androidVersion < 30 ||
- !await AndroidPermissionManager.check(kRecordAudio)) {
- _audioOk = false;
- bind.mainSetOption(key: kOptionEnableAudio, value: "N");
- } else {
- final audioOption = await bind.mainGetOption(key: kOptionEnableAudio);
- _audioOk = audioOption != 'N';
- }
- // file
- if (!await AndroidPermissionManager.check(kManageExternalStorage)) {
- _fileOk = false;
- bind.mainSetOption(key: kOptionEnableFileTransfer, value: "N");
- } else {
- final fileOption =
- await bind.mainGetOption(key: kOptionEnableFileTransfer);
- _fileOk = fileOption != 'N';
- }
- // clipboard
- final clipOption = await bind.mainGetOption(key: kOptionEnableClipboard);
- _clipboardOk = clipOption != 'N';
- notifyListeners();
- }
- updatePasswordModel() async {
- var update = false;
- final temporaryPassword = await bind.mainGetTemporaryPassword();
- final verificationMethod =
- await bind.mainGetOption(key: kOptionVerificationMethod);
- final temporaryPasswordLength =
- await bind.mainGetOption(key: "temporary-password-length");
- final approveMode = await bind.mainGetOption(key: kOptionApproveMode);
- /*
- var hideCm = option2bool(
- 'allow-hide-cm', await bind.mainGetOption(key: 'allow-hide-cm'));
- if (!(approveMode == 'password' &&
- verificationMethod == kUsePermanentPassword)) {
- hideCm = false;
- }
- */
- if (_approveMode != approveMode) {
- _approveMode = approveMode;
- update = true;
- }
- var stopped = await mainGetBoolOption(kOptionStopService);
- final oldPwdText = _serverPasswd.text;
- if (stopped ||
- verificationMethod == kUsePermanentPassword ||
- _approveMode == 'click') {
- _serverPasswd.text = '-';
- } else {
- if (_serverPasswd.text != temporaryPassword &&
- temporaryPassword.isNotEmpty) {
- _serverPasswd.text = temporaryPassword;
- }
- }
- if (oldPwdText != _serverPasswd.text) {
- update = true;
- }
- if (_verificationMethod != verificationMethod) {
- _verificationMethod = verificationMethod;
- update = true;
- }
- if (_temporaryPasswordLength != temporaryPasswordLength) {
- if (_temporaryPasswordLength.isNotEmpty) {
- bind.mainUpdateTemporaryPassword();
- }
- _temporaryPasswordLength = temporaryPasswordLength;
- update = true;
- }
- /*
- if (_hideCm != hideCm) {
- _hideCm = hideCm;
- if (desktopType == DesktopType.cm) {
- if (hideCm) {
- await hideCmWindow();
- } else {
- await showCmWindow();
- }
- }
- update = true;
- }
- */
- if (update) {
- notifyListeners();
- }
- }
- toggleAudio() async {
- if (clients.isNotEmpty) {
- await showClientsMayNotBeChangedAlert(parent.target);
- }
- if (!_audioOk && !await AndroidPermissionManager.check(kRecordAudio)) {
- final res = await AndroidPermissionManager.request(kRecordAudio);
- if (!res) {
- showToast(translate('Failed'));
- return;
- }
- }
- _audioOk = !_audioOk;
- bind.mainSetOption(
- key: kOptionEnableAudio, value: _audioOk ? defaultOptionYes : 'N');
- notifyListeners();
- }
- toggleFile() async {
- if (clients.isNotEmpty) {
- await showClientsMayNotBeChangedAlert(parent.target);
- }
- if (!_fileOk &&
- !await AndroidPermissionManager.check(kManageExternalStorage)) {
- final res =
- await AndroidPermissionManager.request(kManageExternalStorage);
- if (!res) {
- showToast(translate('Failed'));
- return;
- }
- }
- _fileOk = !_fileOk;
- bind.mainSetOption(
- key: kOptionEnableFileTransfer,
- value: _fileOk ? defaultOptionYes : 'N');
- notifyListeners();
- }
- toggleClipboard() async {
- _clipboardOk = !_clipboardOk;
- bind.mainSetOption(
- key: kOptionEnableClipboard,
- value: _clipboardOk ? defaultOptionYes : 'N');
- notifyListeners();
- }
- toggleInput() async {
- if (clients.isNotEmpty) {
- await showClientsMayNotBeChangedAlert(parent.target);
- }
- if (_inputOk) {
- parent.target?.invokeMethod("stop_input");
- bind.mainSetOption(key: kOptionEnableKeyboard, value: 'N');
- } else {
- if (parent.target != null) {
- /// the result of toggle-on depends on user actions in the settings page.
- /// handle result, see [ServerModel.changeStatue]
- showInputWarnAlert(parent.target!);
- }
- }
- }
- Future<bool> checkRequestNotificationPermission() async {
- debugPrint("androidVersion $androidVersion");
- if (androidVersion < 33) {
- return true;
- }
- if (await AndroidPermissionManager.check(kAndroid13Notification)) {
- debugPrint("notification permission already granted");
- return true;
- }
- var res = await AndroidPermissionManager.request(kAndroid13Notification);
- debugPrint("notification permission request result: $res");
- return res;
- }
- Future<bool> checkFloatingWindowPermission() async {
- debugPrint("androidVersion $androidVersion");
- if (androidVersion < 23) {
- return false;
- }
- if (await AndroidPermissionManager.check(kSystemAlertWindow)) {
- debugPrint("alert window permission already granted");
- return true;
- }
- var res = await AndroidPermissionManager.request(kSystemAlertWindow);
- debugPrint("alert window permission request result: $res");
- return res;
- }
- /// Toggle the screen sharing service.
- toggleService() async {
- if (_isStart) {
- final res = await parent.target?.dialogManager
- .show<bool>((setState, close, context) {
- submit() => close(true);
- return CustomAlertDialog(
- title: Row(children: [
- const Icon(Icons.warning_amber_sharp,
- color: Colors.redAccent, size: 28),
- const SizedBox(width: 10),
- Text(translate("Warning")),
- ]),
- content: Text(translate("android_stop_service_tip")),
- actions: [
- TextButton(onPressed: close, child: Text(translate("Cancel"))),
- TextButton(onPressed: submit, child: Text(translate("OK"))),
- ],
- onSubmit: submit,
- onCancel: close,
- );
- });
- if (res == true) {
- stopService();
- }
- } else {
- await checkRequestNotificationPermission();
- if (bind.mainGetLocalOption(key: kOptionDisableFloatingWindow) != 'Y') {
- await checkFloatingWindowPermission();
- }
- if (!await AndroidPermissionManager.check(kManageExternalStorage)) {
- await AndroidPermissionManager.request(kManageExternalStorage);
- }
- final res = await parent.target?.dialogManager
- .show<bool>((setState, close, context) {
- submit() => close(true);
- return CustomAlertDialog(
- title: Row(children: [
- const Icon(Icons.warning_amber_sharp,
- color: Colors.redAccent, size: 28),
- const SizedBox(width: 10),
- Text(translate("Warning")),
- ]),
- content: Text(translate("android_service_will_start_tip")),
- actions: [
- dialogButton("Cancel", onPressed: close, isOutline: true),
- dialogButton("OK", onPressed: submit),
- ],
- onSubmit: submit,
- onCancel: close,
- );
- });
- if (res == true) {
- startService();
- }
- }
- }
- /// Start the screen sharing service.
- Future<void> startService() async {
- _isStart = true;
- notifyListeners();
- parent.target?.ffiModel.updateEventListener(parent.target!.sessionId, "");
- await parent.target?.invokeMethod("init_service");
- // ugly is here, because for desktop, below is useless
- await bind.mainStartService();
- updateClientState();
- if (isAndroid) {
- androidUpdatekeepScreenOn();
- }
- }
- /// Stop the screen sharing service.
- Future<void> stopService() async {
- _isStart = false;
- closeAll();
- await parent.target?.invokeMethod("stop_service");
- await bind.mainStopService();
- notifyListeners();
- if (!isLinux) {
- // current linux is not supported
- WakelockPlus.disable();
- }
- }
- Future<bool> setPermanentPassword(String newPW) async {
- await bind.mainSetPermanentPassword(password: newPW);
- await Future.delayed(Duration(milliseconds: 500));
- final pw = await bind.mainGetPermanentPassword();
- if (newPW == pw) {
- return true;
- } else {
- return false;
- }
- }
- fetchID() async {
- final id = await bind.mainGetMyId();
- if (id != _serverId.id) {
- _serverId.id = id;
- notifyListeners();
- }
- }
- changeStatue(String name, bool value) {
- debugPrint("changeStatue value $value");
- switch (name) {
- case "media":
- _mediaOk = value;
- if (value && !_isStart) {
- startService();
- }
- break;
- case "input":
- if (_inputOk != value) {
- bind.mainSetOption(
- key: kOptionEnableKeyboard,
- value: value ? defaultOptionYes : 'N');
- }
- _inputOk = value;
- break;
- default:
- return;
- }
- notifyListeners();
- }
- // force
- updateClientState([String? json]) async {
- if (isTest) return;
- var res = await bind.cmGetClientsState();
- List<dynamic> clientsJson;
- try {
- clientsJson = jsonDecode(res);
- } catch (e) {
- debugPrint("Failed to decode clientsJson: '$res', error $e");
- return;
- }
- final oldClientLenght = _clients.length;
- _clients.clear();
- tabController.state.value.tabs.clear();
- for (var clientJson in clientsJson) {
- try {
- final client = Client.fromJson(clientJson);
- _clients.add(client);
- _addTab(client);
- } catch (e) {
- debugPrint("Failed to decode clientJson '$clientJson', error $e");
- }
- }
- if (desktopType == DesktopType.cm) {
- if (_clients.isEmpty) {
- hideCmWindow();
- } else if (!hideCm) {
- showCmWindow();
- }
- }
- if (_clients.length != oldClientLenght) {
- notifyListeners();
- if (isAndroid) androidUpdatekeepScreenOn();
- }
- }
- void addConnection(Map<String, dynamic> evt) {
- try {
- final client = Client.fromJson(jsonDecode(evt["client"]));
- if (client.authorized) {
- parent.target?.dialogManager.dismissByTag(getLoginDialogTag(client.id));
- final index = _clients.indexWhere((c) => c.id == client.id);
- if (index < 0) {
- _clients.add(client);
- } else {
- _clients[index].authorized = true;
- }
- } else {
- if (_clients.any((c) => c.id == client.id)) {
- return;
- }
- _clients.add(client);
- }
- _addTab(client);
- // remove disconnected
- final index_disconnected = _clients
- .indexWhere((c) => c.disconnected && c.peerId == client.peerId);
- if (index_disconnected >= 0) {
- _clients.removeAt(index_disconnected);
- tabController.remove(index_disconnected);
- }
- if (desktopType == DesktopType.cm && !hideCm) {
- showCmWindow();
- }
- scrollToBottom();
- notifyListeners();
- if (isAndroid && !client.authorized) showLoginDialog(client);
- if (isAndroid) androidUpdatekeepScreenOn();
- } catch (e) {
- debugPrint("Failed to call loginRequest,error:$e");
- }
- }
- void _addTab(Client client) {
- tabController.add(TabInfo(
- key: client.id.toString(),
- label: client.name,
- closable: false,
- onTap: () {},
- page: desktop.buildConnectionCard(client)));
- Future.delayed(Duration.zero, () async {
- if (!hideCm) windowOnTop(null);
- });
- // Only do the hidden task when on Desktop.
- if (client.authorized && isDesktop) {
- cmHiddenTimer = Timer(const Duration(seconds: 3), () {
- if (!hideCm) windowManager.minimize();
- cmHiddenTimer = null;
- });
- }
- parent.target?.chatModel
- .updateConnIdOfKey(MessageKey(client.peerId, client.id));
- }
- void showLoginDialog(Client client) {
- showClientDialog(
- client,
- client.isFileTransfer ? "File Connection" : "Screen Connection",
- 'Do you accept?',
- 'android_new_connection_tip',
- () => sendLoginResponse(client, false),
- () => sendLoginResponse(client, true),
- );
- }
- handleVoiceCall(Client client, bool accept) {
- parent.target?.invokeMethod("cancel_notification", client.id);
- bind.cmHandleIncomingVoiceCall(id: client.id, accept: accept);
- }
- showVoiceCallDialog(Client client) {
- showClientDialog(
- client,
- 'Voice call',
- 'Do you accept?',
- 'android_new_voice_call_tip',
- () => handleVoiceCall(client, false),
- () => handleVoiceCall(client, true),
- );
- }
- showClientDialog(Client client, String title, String contentTitle,
- String content, VoidCallback onCancel, VoidCallback onSubmit) {
- parent.target?.dialogManager.show((setState, close, context) {
- cancel() {
- onCancel();
- close();
- }
- submit() {
- onSubmit();
- close();
- }
- return CustomAlertDialog(
- title:
- Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
- Text(translate(title)),
- IconButton(onPressed: close, icon: const Icon(Icons.close))
- ]),
- content: Column(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(translate(contentTitle)),
- ClientInfo(client),
- Text(
- translate(content),
- style: Theme.of(globalKey.currentContext!).textTheme.bodyMedium,
- ),
- ],
- ),
- actions: [
- dialogButton("Dismiss", onPressed: cancel, isOutline: true),
- if (approveMode != 'password')
- dialogButton("Accept", onPressed: submit),
- ],
- onSubmit: submit,
- onCancel: cancel,
- );
- }, tag: getLoginDialogTag(client.id));
- }
- scrollToBottom() {
- if (isDesktop) return;
- Future.delayed(Duration(milliseconds: 200), () {
- controller.animateTo(controller.position.maxScrollExtent,
- duration: Duration(milliseconds: 200),
- curve: Curves.fastLinearToSlowEaseIn);
- });
- }
- void sendLoginResponse(Client client, bool res) async {
- if (res) {
- bind.cmLoginRes(connId: client.id, res: res);
- if (!client.isFileTransfer) {
- parent.target?.invokeMethod("start_capture");
- }
- parent.target?.invokeMethod("cancel_notification", client.id);
- client.authorized = true;
- notifyListeners();
- } else {
- bind.cmLoginRes(connId: client.id, res: res);
- parent.target?.invokeMethod("cancel_notification", client.id);
- final index = _clients.indexOf(client);
- tabController.remove(index);
- _clients.remove(client);
- if (isAndroid) androidUpdatekeepScreenOn();
- }
- }
- void onClientRemove(Map<String, dynamic> evt) {
- try {
- final id = int.parse(evt['id'] as String);
- final close = (evt['close'] as String) == 'true';
- if (_clients.any((c) => c.id == id)) {
- final index = _clients.indexWhere((client) => client.id == id);
- if (index >= 0) {
- if (close) {
- _clients.removeAt(index);
- tabController.remove(index);
- } else {
- _clients[index].disconnected = true;
- }
- }
- parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id));
- parent.target?.invokeMethod("cancel_notification", id);
- }
- if (desktopType == DesktopType.cm && _clients.isEmpty) {
- hideCmWindow();
- }
- if (isAndroid) androidUpdatekeepScreenOn();
- notifyListeners();
- } catch (e) {
- debugPrint("onClientRemove failed,error:$e");
- }
- }
- Future<void> closeAll() async {
- await Future.wait(
- _clients.map((client) => bind.cmCloseConnection(connId: client.id)));
- _clients.clear();
- tabController.state.value.tabs.clear();
- if (isAndroid) androidUpdatekeepScreenOn();
- }
- void jumpTo(int id) {
- final index = _clients.indexWhere((client) => client.id == id);
- tabController.jumpTo(index);
- }
- void setShowElevation(bool show) {
- if (_showElevation != show) {
- _showElevation = show;
- notifyListeners();
- }
- }
- void updateVoiceCallState(Map<String, dynamic> evt) {
- try {
- final client = Client.fromJson(jsonDecode(evt["client"]));
- final index = _clients.indexWhere((element) => element.id == client.id);
- if (index != -1) {
- _clients[index].inVoiceCall = client.inVoiceCall;
- _clients[index].incomingVoiceCall = client.incomingVoiceCall;
- if (client.incomingVoiceCall) {
- if (isAndroid) {
- showVoiceCallDialog(client);
- } else {
- // Has incoming phone call, let's set the window on top.
- Future.delayed(Duration.zero, () {
- windowOnTop(null);
- });
- }
- }
- notifyListeners();
- }
- } catch (e) {
- debugPrint("updateVoiceCallState failed: $e");
- }
- }
- void androidUpdatekeepScreenOn() async {
- if (!isAndroid) return;
- var floatingWindowDisabled =
- bind.mainGetLocalOption(key: kOptionDisableFloatingWindow) == "Y" ||
- !await AndroidPermissionManager.check(kSystemAlertWindow);
- final keepScreenOn = floatingWindowDisabled
- ? KeepScreenOn.never
- : optionToKeepScreenOn(
- bind.mainGetLocalOption(key: kOptionKeepScreenOn));
- final on = ((keepScreenOn == KeepScreenOn.serviceOn) && _isStart) ||
- (keepScreenOn == KeepScreenOn.duringControlled &&
- _clients.map((e) => !e.disconnected).isNotEmpty);
- if (on != await WakelockPlus.enabled) {
- if (on) {
- WakelockPlus.enable();
- } else {
- WakelockPlus.disable();
- }
- }
- }
- }
- enum ClientType {
- remote,
- file,
- portForward,
- }
- class Client {
- int id = 0; // client connections inner count id
- bool authorized = false;
- bool isFileTransfer = false;
- String portForward = "";
- String name = "";
- String peerId = ""; // peer user's id,show at app
- bool keyboard = false;
- bool clipboard = false;
- bool audio = false;
- bool file = false;
- bool restart = false;
- bool recording = false;
- bool blockInput = false;
- bool disconnected = false;
- bool fromSwitch = false;
- bool inVoiceCall = false;
- bool incomingVoiceCall = false;
- RxInt unreadChatMessageCount = 0.obs;
- Client(this.id, this.authorized, this.isFileTransfer, this.name, this.peerId,
- this.keyboard, this.clipboard, this.audio);
- Client.fromJson(Map<String, dynamic> json) {
- id = json['id'];
- authorized = json['authorized'];
- isFileTransfer = json['is_file_transfer'];
- portForward = json['port_forward'];
- name = json['name'];
- peerId = json['peer_id'];
- keyboard = json['keyboard'];
- clipboard = json['clipboard'];
- audio = json['audio'];
- file = json['file'];
- restart = json['restart'];
- recording = json['recording'];
- blockInput = json['block_input'];
- disconnected = json['disconnected'];
- fromSwitch = json['from_switch'];
- inVoiceCall = json['in_voice_call'];
- incomingVoiceCall = json['incoming_voice_call'];
- }
- Map<String, dynamic> toJson() {
- final Map<String, dynamic> data = <String, dynamic>{};
- data['id'] = id;
- data['authorized'] = authorized;
- data['is_file_transfer'] = isFileTransfer;
- data['port_forward'] = portForward;
- data['name'] = name;
- data['peer_id'] = peerId;
- data['keyboard'] = keyboard;
- data['clipboard'] = clipboard;
- data['audio'] = audio;
- data['file'] = file;
- data['restart'] = restart;
- data['recording'] = recording;
- data['block_input'] = blockInput;
- data['disconnected'] = disconnected;
- data['from_switch'] = fromSwitch;
- data['in_voice_call'] = inVoiceCall;
- data['incoming_voice_call'] = incomingVoiceCall;
- return data;
- }
- ClientType type_() {
- if (isFileTransfer) {
- return ClientType.file;
- } else if (portForward.isNotEmpty) {
- return ClientType.portForward;
- } else {
- return ClientType.remote;
- }
- }
- }
- String getLoginDialogTag(int id) {
- return kLoginDialogTag + id.toString();
- }
- showInputWarnAlert(FFI ffi) {
- ffi.dialogManager.show((setState, close, context) {
- submit() {
- AndroidPermissionManager.startAction(kActionAccessibilitySettings);
- close();
- }
- return CustomAlertDialog(
- title: Text(translate("How to get Android input permission?")),
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(translate("android_input_permission_tip1")),
- const SizedBox(height: 10),
- Text(translate("android_input_permission_tip2")),
- ],
- ),
- actions: [
- dialogButton("Cancel", onPressed: close, isOutline: true),
- dialogButton("Open System Setting", onPressed: submit),
- ],
- onSubmit: submit,
- onCancel: close,
- );
- });
- }
- Future<void> showClientsMayNotBeChangedAlert(FFI? ffi) async {
- await ffi?.dialogManager.show((setState, close, context) {
- return CustomAlertDialog(
- title: Text(translate("Permissions")),
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(translate("android_permission_may_not_change_tip")),
- ],
- ),
- actions: [
- dialogButton("OK", onPressed: close),
- ],
- onSubmit: close,
- onCancel: close,
- );
- });
- }
|