Merge pull request #2299 from fufesou/refact_remote_menubar
hide zoom-cursor if view-style is original
This commit is contained in:
commit
93e0533c84
@ -70,6 +70,30 @@ const kMouseControlDistance = 12;
|
|||||||
/// [kMouseControlTimeoutMSec] indicates the timeout (in milliseconds) that self-side can get control of mouse.
|
/// [kMouseControlTimeoutMSec] indicates the timeout (in milliseconds) that self-side can get control of mouse.
|
||||||
const kMouseControlTimeoutMSec = 1000;
|
const kMouseControlTimeoutMSec = 1000;
|
||||||
|
|
||||||
|
/// [kRemoteViewStyleOriginal] Show remote image without scaling.
|
||||||
|
const kRemoteViewStyleOriginal = 'original';
|
||||||
|
|
||||||
|
/// [kRemoteViewStyleAdaptive] Show remote image scaling by ratio factor.
|
||||||
|
const kRemoteViewStyleAdaptive = 'adaptive';
|
||||||
|
|
||||||
|
/// [kRemoteScrollStyleAuto] Scroll image auto by position.
|
||||||
|
const kRemoteScrollStyleAuto = 'scrollauto';
|
||||||
|
|
||||||
|
/// [kRemoteScrollStyleBar] Scroll image with scroll bar.
|
||||||
|
const kRemoteScrollStyleBar = 'scrollbar';
|
||||||
|
|
||||||
|
/// [kRemoteImageQualityBest] Best image quality.
|
||||||
|
const kRemoteImageQualityBest = 'best';
|
||||||
|
|
||||||
|
/// [kRemoteImageQualityBalanced] Balanced image quality, mid performance.
|
||||||
|
const kRemoteImageQualityBalanced = 'balanced';
|
||||||
|
|
||||||
|
/// [kRemoteImageQualityLow] Low image quality, better performance.
|
||||||
|
const kRemoteImageQualityLow = 'low';
|
||||||
|
|
||||||
|
/// [kRemoteImageQualityCustom] Custom image quality.
|
||||||
|
const kRemoteImageQualityCustom = 'custom';
|
||||||
|
|
||||||
/// flutter/packages/flutter/lib/src/services/keyboard_key.dart -> _keyLabels
|
/// flutter/packages/flutter/lib/src/services/keyboard_key.dart -> _keyLabels
|
||||||
/// see [LogicalKeyboardKey.keyLabel]
|
/// see [LogicalKeyboardKey.keyLabel]
|
||||||
const Map<int, String> logicalKeyMap = <int, String>{
|
const Map<int, String> logicalKeyMap = <int, String>{
|
||||||
|
@ -236,12 +236,12 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
optionsGetter: () => [
|
optionsGetter: () => [
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Scale original'),
|
text: translate('Scale original'),
|
||||||
value: 'original',
|
value: kRemoteViewStyleOriginal,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Scale adaptive'),
|
text: translate('Scale adaptive'),
|
||||||
value: 'adaptive',
|
value: kRemoteViewStyleAdaptive,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -249,8 +249,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
// null means peer id is not found, which there's no need to care about
|
// null means peer id is not found, which there's no need to care about
|
||||||
await bind.sessionGetViewStyle(id: key) ?? '',
|
await bind.sessionGetViewStyle(id: key) ?? '',
|
||||||
optionSetter: (String oldValue, String newValue) async {
|
optionSetter: (String oldValue, String newValue) async {
|
||||||
await bind.sessionSetViewStyle(
|
await bind.sessionSetViewStyle(id: key, value: newValue);
|
||||||
id: key, value: newValue);
|
|
||||||
ffi.canvasModel.updateViewStyle();
|
ffi.canvasModel.updateViewStyle();
|
||||||
cancelFunc();
|
cancelFunc();
|
||||||
},
|
},
|
||||||
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hbb/models/chat_model.dart';
|
import 'package:flutter_hbb/models/chat_model.dart';
|
||||||
import 'package:flutter_hbb/models/state_model.dart';
|
import 'package:flutter_hbb/models/state_model.dart';
|
||||||
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:rxdart/rxdart.dart' as rxdart;
|
import 'package:rxdart/rxdart.dart' as rxdart;
|
||||||
@ -25,6 +26,7 @@ class MenubarState {
|
|||||||
final kStoreKey = 'remoteMenubarState';
|
final kStoreKey = 'remoteMenubarState';
|
||||||
late RxBool show;
|
late RxBool show;
|
||||||
late RxBool _pin;
|
late RxBool _pin;
|
||||||
|
RxString viewStyle = RxString(kRemoteViewStyleOriginal);
|
||||||
|
|
||||||
MenubarState() {
|
MenubarState() {
|
||||||
final s = bind.getLocalFlutterConfig(k: kStoreKey);
|
final s = bind.getLocalFlutterConfig(k: kStoreKey);
|
||||||
@ -67,21 +69,25 @@ class MenubarState {
|
|||||||
switchPin() async {
|
switchPin() async {
|
||||||
_pin.value = !_pin.value;
|
_pin.value = !_pin.value;
|
||||||
// Save everytime changed, as this func will not be called frequently
|
// Save everytime changed, as this func will not be called frequently
|
||||||
await save();
|
await _savePin();
|
||||||
}
|
}
|
||||||
|
|
||||||
setPin(bool v) async {
|
setPin(bool v) async {
|
||||||
if (_pin.value != v) {
|
if (_pin.value != v) {
|
||||||
_pin.value = v;
|
_pin.value = v;
|
||||||
// Save everytime changed, as this func will not be called frequently
|
// Save everytime changed, as this func will not be called frequently
|
||||||
await save();
|
await _savePin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
save() async {
|
_savePin() async {
|
||||||
bind.setLocalFlutterConfig(
|
bind.setLocalFlutterConfig(
|
||||||
k: kStoreKey, v: jsonEncode({'pin': _pin.value}));
|
k: kStoreKey, v: jsonEncode({'pin': _pin.value}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
save() async {
|
||||||
|
await _savePin();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MenubarTheme {
|
class _MenubarTheme {
|
||||||
@ -404,6 +410,8 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
|
|
||||||
Widget _buildDisplay(BuildContext context) {
|
Widget _buildDisplay(BuildContext context) {
|
||||||
return FutureBuilder(future: () async {
|
return FutureBuilder(future: () async {
|
||||||
|
widget.state.viewStyle.value =
|
||||||
|
await bind.sessionGetViewStyle(id: widget.id) ?? '';
|
||||||
final supportedHwcodec =
|
final supportedHwcodec =
|
||||||
await bind.sessionSupportedHwcodec(id: widget.id);
|
await bind.sessionSupportedHwcodec(id: widget.id);
|
||||||
return {'supportedHwcodec': supportedHwcodec};
|
return {'supportedHwcodec': supportedHwcodec};
|
||||||
@ -719,20 +727,24 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
optionsGetter: () => [
|
optionsGetter: () => [
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Scale original'),
|
text: translate('Scale original'),
|
||||||
value: 'original',
|
value: kRemoteViewStyleOriginal,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Scale adaptive'),
|
text: translate('Scale adaptive'),
|
||||||
value: 'adaptive',
|
value: kRemoteViewStyleAdaptive,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
curOptionGetter: () async =>
|
curOptionGetter: () async {
|
||||||
// null means peer id is not found, which there's no need to care about
|
// null means peer id is not found, which there's no need to care about
|
||||||
await bind.sessionGetViewStyle(id: widget.id) ?? '',
|
final viewStyle = await bind.sessionGetViewStyle(id: widget.id) ?? '';
|
||||||
|
widget.state.viewStyle.value = viewStyle;
|
||||||
|
return viewStyle;
|
||||||
|
},
|
||||||
optionSetter: (String oldValue, String newValue) async {
|
optionSetter: (String oldValue, String newValue) async {
|
||||||
await bind.sessionSetViewStyle(id: widget.id, value: newValue);
|
await bind.sessionSetViewStyle(id: widget.id, value: newValue);
|
||||||
|
widget.state.viewStyle.value = newValue;
|
||||||
widget.ffi.canvasModel.updateViewStyle();
|
widget.ffi.canvasModel.updateViewStyle();
|
||||||
},
|
},
|
||||||
padding: padding,
|
padding: padding,
|
||||||
@ -744,12 +756,12 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
optionsGetter: () => [
|
optionsGetter: () => [
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('ScrollAuto'),
|
text: translate('ScrollAuto'),
|
||||||
value: 'scrollauto',
|
value: kRemoteScrollStyleAuto,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Scrollbar'),
|
text: translate('Scrollbar'),
|
||||||
value: 'scrollbar',
|
value: kRemoteScrollStyleBar,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -769,22 +781,22 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
optionsGetter: () => [
|
optionsGetter: () => [
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Good image quality'),
|
text: translate('Good image quality'),
|
||||||
value: 'best',
|
value: kRemoteImageQualityBest,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Balanced'),
|
text: translate('Balanced'),
|
||||||
value: 'balanced',
|
value: kRemoteImageQualityBalanced,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Optimize reaction time'),
|
text: translate('Optimize reaction time'),
|
||||||
value: 'low',
|
value: kRemoteImageQualityLow,
|
||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
),
|
),
|
||||||
MenuEntryRadioOption(
|
MenuEntryRadioOption(
|
||||||
text: translate('Custom'),
|
text: translate('Custom'),
|
||||||
value: 'custom',
|
value: kRemoteImageQualityCustom,
|
||||||
dismissOnClicked: true),
|
dismissOnClicked: true),
|
||||||
],
|
],
|
||||||
curOptionGetter: () async =>
|
curOptionGetter: () async =>
|
||||||
@ -821,7 +833,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValue == 'custom') {
|
if (newValue == kRemoteImageQualityCustom) {
|
||||||
final btnClose = msgBoxButton(translate('Close'), () async {
|
final btnClose = msgBoxButton(translate('Close'), () async {
|
||||||
await setCustomValues();
|
await setCustomValues();
|
||||||
widget.ffi.dialogManager.dismissAll();
|
widget.ffi.dialogManager.dismissAll();
|
||||||
@ -1089,7 +1101,8 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
);
|
);
|
||||||
}());
|
}());
|
||||||
|
|
||||||
/// Show remote cursor
|
/// Show remote cursor scaling with image
|
||||||
|
if (widget.state.viewStyle.value != kRemoteViewStyleOriginal) {
|
||||||
displayMenu.add(() {
|
displayMenu.add(() {
|
||||||
final opt = 'zoom-cursor';
|
final opt = 'zoom-cursor';
|
||||||
final state = PeerBoolOption.find(widget.id, opt);
|
final state = PeerBoolOption.find(widget.id, opt);
|
||||||
@ -1107,6 +1120,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
);
|
);
|
||||||
}());
|
}());
|
||||||
|
}
|
||||||
|
|
||||||
/// Show quality monitor
|
/// Show quality monitor
|
||||||
displayMenu.add(MenuEntrySwitch<String>(
|
displayMenu.add(MenuEntrySwitch<String>(
|
||||||
@ -1179,7 +1193,6 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
optionSetter: (String oldValue, String newValue) async {
|
optionSetter: (String oldValue, String newValue) async {
|
||||||
await bind.sessionSetKeyboardMode(
|
await bind.sessionSetKeyboardMode(
|
||||||
id: widget.id, keyboardMode: newValue);
|
id: widget.id, keyboardMode: newValue);
|
||||||
widget.ffi.canvasModel.updateViewStyle();
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
@ -4,6 +4,7 @@ import 'dart:ui' as ui;
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:flutter_hbb/mobile/widgets/gesture_help.dart';
|
import 'package:flutter_hbb/mobile/widgets/gesture_help.dart';
|
||||||
import 'package:flutter_hbb/models/chat_model.dart';
|
import 'package:flutter_hbb/models/chat_model.dart';
|
||||||
import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
|
import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
|
||||||
@ -642,7 +643,7 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
// FIXME:
|
// FIXME:
|
||||||
// null means no session of id
|
// null means no session of id
|
||||||
// empty string means no password
|
// empty string means no password
|
||||||
var password = await bind.sessionGetOption(id: id, arg: "os-password");
|
var password = await bind.sessionGetOption(id: id, arg: 'os-password');
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
bind.sessionInputOsPassword(id: widget.id, value: password);
|
bind.sessionInputOsPassword(id: widget.id, value: password);
|
||||||
} else {
|
} else {
|
||||||
@ -908,13 +909,13 @@ class ImagePainter extends CustomPainter {
|
|||||||
|
|
||||||
void showOptions(
|
void showOptions(
|
||||||
BuildContext context, String id, OverlayDialogManager dialogManager) async {
|
BuildContext context, String id, OverlayDialogManager dialogManager) async {
|
||||||
String quality = await bind.sessionGetImageQuality(id: id) ?? 'balanced';
|
String quality =
|
||||||
if (quality == '') quality = 'balanced';
|
await bind.sessionGetImageQuality(id: id) ?? kRemoteImageQualityBalanced;
|
||||||
|
if (quality == '') quality = kRemoteImageQualityBalanced;
|
||||||
String codec =
|
String codec =
|
||||||
await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? 'auto';
|
await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? 'auto';
|
||||||
if (codec == '') codec = 'auto';
|
if (codec == '') codec = 'auto';
|
||||||
String viewStyle =
|
String viewStyle = await bind.sessionGetViewStyle(id: id) ?? '';
|
||||||
await bind.sessionGetOption(id: id, arg: 'view-style') ?? '';
|
|
||||||
|
|
||||||
var displays = <Widget>[];
|
var displays = <Widget>[];
|
||||||
final pi = gFFI.ffiModel.pi;
|
final pi = gFFI.ffiModel.pi;
|
||||||
@ -1017,12 +1018,16 @@ void showOptions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
final radios = [
|
final radios = [
|
||||||
getRadio('Scale original', 'original', viewStyle, setViewStyle),
|
getRadio(
|
||||||
getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle),
|
'Scale original', kRemoteViewStyleOriginal, viewStyle, setViewStyle),
|
||||||
|
getRadio(
|
||||||
|
'Scale adaptive', kRemoteViewStyleAdaptive, viewStyle, setViewStyle),
|
||||||
const Divider(color: MyTheme.border),
|
const Divider(color: MyTheme.border),
|
||||||
getRadio('Good image quality', 'best', quality, setQuality),
|
getRadio(
|
||||||
getRadio('Balanced', 'balanced', quality, setQuality),
|
'Good image quality', kRemoteImageQualityBest, quality, setQuality),
|
||||||
getRadio('Optimize reaction time', 'low', quality, setQuality),
|
getRadio('Balanced', kRemoteImageQualityBalanced, quality, setQuality),
|
||||||
|
getRadio('Optimize reaction time', kRemoteImageQualityLow, quality,
|
||||||
|
setQuality),
|
||||||
const Divider(color: MyTheme.border)
|
const Divider(color: MyTheme.border)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -565,7 +565,7 @@ class CanvasModel with ChangeNotifier {
|
|||||||
|
|
||||||
updateScrollStyle() async {
|
updateScrollStyle() async {
|
||||||
final style = await bind.sessionGetScrollStyle(id: id);
|
final style = await bind.sessionGetScrollStyle(id: id);
|
||||||
if (style == 'scrollbar') {
|
if (style == kRemoteScrollStyleBar) {
|
||||||
_scrollStyle = ScrollStyle.scrollbar;
|
_scrollStyle = ScrollStyle.scrollbar;
|
||||||
_scrollX = 0.0;
|
_scrollX = 0.0;
|
||||||
_scrollY = 0.0;
|
_scrollY = 0.0;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ffi::{OsStr, OsString},
|
|
||||||
fs,
|
fs,
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
@ -896,13 +895,13 @@ impl PeerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn path(id: &str) -> PathBuf {
|
fn path(id: &str) -> PathBuf {
|
||||||
let mut id_encoded: String;
|
let id_encoded: String;
|
||||||
|
|
||||||
//If the id contains invalid chars, encode it
|
//If the id contains invalid chars, encode it
|
||||||
let forbidden_paths = Regex::new(r".*[<>:/\\|\?\*].*").unwrap();
|
let forbidden_paths = Regex::new(r".*[<>:/\\|\?\*].*").unwrap();
|
||||||
if forbidden_paths.is_match(id) {
|
if forbidden_paths.is_match(id) {
|
||||||
id_encoded =
|
id_encoded =
|
||||||
("base64_".to_string() + base64::encode(id, base64::Variant::Original).as_str())
|
"base64_".to_string() + base64::encode(id, base64::Variant::Original).as_str();
|
||||||
} else {
|
} else {
|
||||||
id_encoded = id.to_string();
|
id_encoded = id.to_string();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user