flutter_desktop: fix cursor, mid commit
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
f37dc72bbf
commit
11c5364e71
@ -1,16 +1,26 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
import '../models/platform_model.dart';
|
||||||
|
|
||||||
class PrivacyModeState {
|
class PrivacyModeState {
|
||||||
static String tag(String id) => 'privacy_mode_$id';
|
static String tag(String id) => 'privacy_mode_$id';
|
||||||
|
|
||||||
static void init(String id) {
|
static void init(String id) {
|
||||||
final RxBool state = false.obs;
|
final key = tag(id);
|
||||||
Get.put(state, tag: tag(id));
|
if (!Get.isRegistered(tag: key)) {
|
||||||
|
final RxBool state = false.obs;
|
||||||
|
Get.put(state, tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (Get.isRegistered(tag: key)) {
|
||||||
|
Get.delete(tag: key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete(String id) => Get.delete(tag: tag(id));
|
|
||||||
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,11 +28,20 @@ class BlockInputState {
|
|||||||
static String tag(String id) => 'block_input_$id';
|
static String tag(String id) => 'block_input_$id';
|
||||||
|
|
||||||
static void init(String id) {
|
static void init(String id) {
|
||||||
final RxBool state = false.obs;
|
final key = tag(id);
|
||||||
Get.put(state, tag: tag(id));
|
if (!Get.isRegistered(tag: key)) {
|
||||||
|
final RxBool state = false.obs;
|
||||||
|
Get.put(state, tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (Get.isRegistered(tag: key)) {
|
||||||
|
Get.delete(tag: key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete(String id) => Get.delete(tag: tag(id));
|
|
||||||
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,11 +49,20 @@ class CurrentDisplayState {
|
|||||||
static String tag(String id) => 'current_display_$id';
|
static String tag(String id) => 'current_display_$id';
|
||||||
|
|
||||||
static void init(String id) {
|
static void init(String id) {
|
||||||
final RxInt state = RxInt(0);
|
final key = tag(id);
|
||||||
Get.put(state, tag: tag(id));
|
if (!Get.isRegistered(tag: key)) {
|
||||||
|
final RxInt state = RxInt(0);
|
||||||
|
Get.put(state, tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (Get.isRegistered(tag: key)) {
|
||||||
|
Get.delete(tag: key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete(String id) => Get.delete(tag: tag(id));
|
|
||||||
static RxInt find(String id) => Get.find<RxInt>(tag: tag(id));
|
static RxInt find(String id) => Get.find<RxInt>(tag: tag(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,3 +113,46 @@ class ConnectionTypeState {
|
|||||||
static ConnectionType find(String id) =>
|
static ConnectionType find(String id) =>
|
||||||
Get.find<ConnectionType>(tag: tag(id));
|
Get.find<ConnectionType>(tag: tag(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShowRemoteCursorState {
|
||||||
|
static String tag(String id) => 'show_remote_cursor_$id';
|
||||||
|
|
||||||
|
static void init(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (!Get.isRegistered(tag: key)) {
|
||||||
|
final RxBool state = false.obs;
|
||||||
|
Get.put(state, tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (Get.isRegistered(tag: key)) {
|
||||||
|
Get.delete(tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
class KeyboardEnabledState {
|
||||||
|
static String tag(String id) => 'keyboard_enabled_$id';
|
||||||
|
|
||||||
|
static void init(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (!Get.isRegistered(tag: key)) {
|
||||||
|
// Server side, default true
|
||||||
|
final RxBool state = true.obs;
|
||||||
|
Get.put(state, tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(String id) {
|
||||||
|
final key = tag(id);
|
||||||
|
if (Get.isRegistered(tag: key)) {
|
||||||
|
Get.delete(tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
||||||
|
}
|
||||||
|
@ -40,6 +40,8 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
String _value = '';
|
String _value = '';
|
||||||
final _cursorOverImage = false.obs;
|
final _cursorOverImage = false.obs;
|
||||||
|
late RxBool _showRemoteCursor;
|
||||||
|
late RxBool _keyboardEnabled;
|
||||||
|
|
||||||
final FocusNode _mobileFocusNode = FocusNode();
|
final FocusNode _mobileFocusNode = FocusNode();
|
||||||
final FocusNode _physicalFocusNode = FocusNode();
|
final FocusNode _physicalFocusNode = FocusNode();
|
||||||
@ -56,17 +58,24 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
PrivacyModeState.init(id);
|
PrivacyModeState.init(id);
|
||||||
BlockInputState.init(id);
|
BlockInputState.init(id);
|
||||||
CurrentDisplayState.init(id);
|
CurrentDisplayState.init(id);
|
||||||
|
KeyboardEnabledState.init(id);
|
||||||
|
ShowRemoteCursorState.init(id);
|
||||||
|
_showRemoteCursor = ShowRemoteCursorState.find(id);
|
||||||
|
_keyboardEnabled = KeyboardEnabledState.find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _removeStates(String id) {
|
void _removeStates(String id) {
|
||||||
PrivacyModeState.delete(id);
|
PrivacyModeState.delete(id);
|
||||||
BlockInputState.delete(id);
|
BlockInputState.delete(id);
|
||||||
CurrentDisplayState.delete(id);
|
CurrentDisplayState.delete(id);
|
||||||
|
ShowRemoteCursorState.delete(id);
|
||||||
|
KeyboardEnabledState.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_initStates(widget.id);
|
||||||
_ffi = FFI();
|
_ffi = FFI();
|
||||||
_updateTabBarHeight();
|
_updateTabBarHeight();
|
||||||
Get.put(_ffi, tag: widget.id);
|
Get.put(_ffi, tag: widget.id);
|
||||||
@ -84,7 +93,8 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
_ffi.listenToMouse(true);
|
_ffi.listenToMouse(true);
|
||||||
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
|
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
|
||||||
// WindowManager.instance.addListener(this);
|
// WindowManager.instance.addListener(this);
|
||||||
_initStates(widget.id);
|
_showRemoteCursor.value = bind.sessionGetToggleOptionSync(
|
||||||
|
id: widget.id, arg: 'show-remote-cursor');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -197,8 +207,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
_ffi.inputKey(label, down: down, press: press ?? false);
|
_ffi.inputKey(label, down: down, press: press ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildBody(BuildContext context, FfiModel ffiModel) {
|
Widget buildBody(BuildContext context) {
|
||||||
final keyboard = ffiModel.permissions['keyboard'] != false;
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: MyTheme.color(context).bg,
|
backgroundColor: MyTheme.color(context).bg,
|
||||||
body: Overlay(
|
body: Overlay(
|
||||||
@ -208,8 +217,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
_ffi.dialogManager.setOverlayState(Overlay.of(context));
|
_ffi.dialogManager.setOverlayState(Overlay.of(context));
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
child: getRawPointerAndKeyBody(
|
child: getRawPointerAndKeyBody(getBodyForDesktop(context)));
|
||||||
getBodyForDesktop(context, keyboard)));
|
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
@ -224,70 +232,61 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
clientClose(_ffi.dialogManager);
|
clientClose(_ffi.dialogManager);
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
child: MultiProvider(
|
child: MultiProvider(providers: [
|
||||||
providers: [
|
ChangeNotifierProvider.value(value: _ffi.ffiModel),
|
||||||
ChangeNotifierProvider.value(value: _ffi.ffiModel),
|
ChangeNotifierProvider.value(value: _ffi.imageModel),
|
||||||
ChangeNotifierProvider.value(value: _ffi.imageModel),
|
ChangeNotifierProvider.value(value: _ffi.cursorModel),
|
||||||
ChangeNotifierProvider.value(value: _ffi.cursorModel),
|
ChangeNotifierProvider.value(value: _ffi.canvasModel),
|
||||||
ChangeNotifierProvider.value(value: _ffi.canvasModel),
|
], child: buildBody(context)));
|
||||||
],
|
|
||||||
child: Consumer<FfiModel>(
|
|
||||||
builder: (context, ffiModel, child) =>
|
|
||||||
buildBody(context, ffiModel))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget getRawPointerAndKeyBody(Widget child) {
|
Widget getRawPointerAndKeyBody(Widget child) {
|
||||||
return Consumer<FfiModel>(
|
return FocusScope(
|
||||||
builder: (context, FfiModel, _child) => MouseRegion(
|
autofocus: true,
|
||||||
cursor: FfiModel.permissions['keyboard'] != false
|
child: Focus(
|
||||||
? SystemMouseCursors.none
|
autofocus: true,
|
||||||
: MouseCursor.defer,
|
canRequestFocus: true,
|
||||||
child: FocusScope(
|
focusNode: _physicalFocusNode,
|
||||||
autofocus: true,
|
onFocusChange: (bool v) {
|
||||||
child: Focus(
|
_imageFocused = v;
|
||||||
autofocus: true,
|
},
|
||||||
canRequestFocus: true,
|
onKey: (data, e) {
|
||||||
focusNode: _physicalFocusNode,
|
final key = e.logicalKey;
|
||||||
onFocusChange: (bool v) {
|
if (e is RawKeyDownEvent) {
|
||||||
_imageFocused = v;
|
if (e.repeat) {
|
||||||
},
|
sendRawKey(e, press: true);
|
||||||
onKey: (data, e) {
|
} else {
|
||||||
final key = e.logicalKey;
|
if (e.isAltPressed && !_ffi.alt) {
|
||||||
if (e is RawKeyDownEvent) {
|
_ffi.alt = true;
|
||||||
if (e.repeat) {
|
} else if (e.isControlPressed && !_ffi.ctrl) {
|
||||||
sendRawKey(e, press: true);
|
_ffi.ctrl = true;
|
||||||
} else {
|
} else if (e.isShiftPressed && !_ffi.shift) {
|
||||||
if (e.isAltPressed && !_ffi.alt) {
|
_ffi.shift = true;
|
||||||
_ffi.alt = true;
|
} else if (e.isMetaPressed && !_ffi.command) {
|
||||||
} else if (e.isControlPressed && !_ffi.ctrl) {
|
_ffi.command = true;
|
||||||
_ffi.ctrl = true;
|
}
|
||||||
} else if (e.isShiftPressed && !_ffi.shift) {
|
sendRawKey(e, down: true);
|
||||||
_ffi.shift = true;
|
}
|
||||||
} else if (e.isMetaPressed && !_ffi.command) {
|
}
|
||||||
_ffi.command = true;
|
if (e is RawKeyUpEvent) {
|
||||||
}
|
if (key == LogicalKeyboardKey.altLeft ||
|
||||||
sendRawKey(e, down: true);
|
key == LogicalKeyboardKey.altRight) {
|
||||||
}
|
_ffi.alt = false;
|
||||||
}
|
} else if (key == LogicalKeyboardKey.controlLeft ||
|
||||||
if (e is RawKeyUpEvent) {
|
key == LogicalKeyboardKey.controlRight) {
|
||||||
if (key == LogicalKeyboardKey.altLeft ||
|
_ffi.ctrl = false;
|
||||||
key == LogicalKeyboardKey.altRight) {
|
} else if (key == LogicalKeyboardKey.shiftRight ||
|
||||||
_ffi.alt = false;
|
key == LogicalKeyboardKey.shiftLeft) {
|
||||||
} else if (key == LogicalKeyboardKey.controlLeft ||
|
_ffi.shift = false;
|
||||||
key == LogicalKeyboardKey.controlRight) {
|
} else if (key == LogicalKeyboardKey.metaLeft ||
|
||||||
_ffi.ctrl = false;
|
key == LogicalKeyboardKey.metaRight) {
|
||||||
} else if (key == LogicalKeyboardKey.shiftRight ||
|
_ffi.command = false;
|
||||||
key == LogicalKeyboardKey.shiftLeft) {
|
}
|
||||||
_ffi.shift = false;
|
sendRawKey(e);
|
||||||
} else if (key == LogicalKeyboardKey.metaLeft ||
|
}
|
||||||
key == LogicalKeyboardKey.metaRight) {
|
return KeyEventResult.handled;
|
||||||
_ffi.command = false;
|
},
|
||||||
}
|
child: child));
|
||||||
sendRawKey(e);
|
|
||||||
}
|
|
||||||
return KeyEventResult.handled;
|
|
||||||
},
|
|
||||||
child: child))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// touchMode only:
|
/// touchMode only:
|
||||||
@ -382,32 +381,30 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
child: child));
|
child: child));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget getBodyForDesktop(BuildContext context, bool keyboard) {
|
Widget getBodyForDesktop(BuildContext context) {
|
||||||
var paints = <Widget>[
|
var paints = <Widget>[
|
||||||
MouseRegion(onEnter: (evt) {
|
MouseRegion(onEnter: (evt) {
|
||||||
bind.hostStopSystemKeyPropagate(stopped: false);
|
bind.hostStopSystemKeyPropagate(stopped: false);
|
||||||
}, onExit: (evt) {
|
}, onExit: (evt) {
|
||||||
bind.hostStopSystemKeyPropagate(stopped: true);
|
bind.hostStopSystemKeyPropagate(stopped: true);
|
||||||
}, child: Container(
|
}, child: LayoutBuilder(builder: (context, constraints) {
|
||||||
child: LayoutBuilder(builder: (context, constraints) {
|
Future.delayed(Duration.zero, () {
|
||||||
Future.delayed(Duration.zero, () {
|
Provider.of<CanvasModel>(context, listen: false).updateViewStyle();
|
||||||
Provider.of<CanvasModel>(context, listen: false).updateViewStyle();
|
});
|
||||||
});
|
return ImagePaint(
|
||||||
return ImagePaint(
|
id: widget.id,
|
||||||
id: widget.id,
|
cursorOverImage: _cursorOverImage,
|
||||||
cursorOverImage: _cursorOverImage,
|
keyboardEnabled: _keyboardEnabled,
|
||||||
listenerBuilder: _buildImageListener,
|
listenerBuilder: _buildImageListener,
|
||||||
);
|
);
|
||||||
}),
|
}))
|
||||||
))
|
|
||||||
];
|
];
|
||||||
final cursor = bind.sessionGetToggleOptionSync(
|
|
||||||
id: widget.id, arg: 'show-remote-cursor');
|
paints.add(Obx(() => Visibility(
|
||||||
if (keyboard || cursor) {
|
visible: _keyboardEnabled.isTrue || _showRemoteCursor.isTrue,
|
||||||
paints.add(CursorPaint(
|
child: CursorPaint(
|
||||||
id: widget.id,
|
id: widget.id,
|
||||||
));
|
))));
|
||||||
}
|
|
||||||
paints.add(QualityMonitor(_ffi.qualityMonitorModel));
|
paints.add(QualityMonitor(_ffi.qualityMonitorModel));
|
||||||
paints.add(RemoteMenubar(
|
paints.add(RemoteMenubar(
|
||||||
id: widget.id,
|
id: widget.id,
|
||||||
@ -447,7 +444,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
_ffi.canvasModel.updateViewStyle();
|
_ffi.canvasModel.updateViewStyle();
|
||||||
break;
|
break;
|
||||||
case 'maximize':
|
case 'maximize':
|
||||||
Future.delayed(Duration(milliseconds: 100), () {
|
Future.delayed(const Duration(milliseconds: 100), () {
|
||||||
_ffi.canvasModel.updateViewStyle();
|
_ffi.canvasModel.updateViewStyle();
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -461,6 +458,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
class ImagePaint extends StatelessWidget {
|
class ImagePaint extends StatelessWidget {
|
||||||
final String id;
|
final String id;
|
||||||
final Rx<bool> cursorOverImage;
|
final Rx<bool> cursorOverImage;
|
||||||
|
final Rx<bool> keyboardEnabled;
|
||||||
final Widget Function(Widget)? listenerBuilder;
|
final Widget Function(Widget)? listenerBuilder;
|
||||||
final ScrollController _horizontal = ScrollController();
|
final ScrollController _horizontal = ScrollController();
|
||||||
final ScrollController _vertical = ScrollController();
|
final ScrollController _vertical = ScrollController();
|
||||||
@ -469,6 +467,7 @@ class ImagePaint extends StatelessWidget {
|
|||||||
{Key? key,
|
{Key? key,
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.cursorOverImage,
|
required this.cursorOverImage,
|
||||||
|
required this.keyboardEnabled,
|
||||||
this.listenerBuilder})
|
this.listenerBuilder})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@ -485,25 +484,26 @@ class ImagePaint extends StatelessWidget {
|
|||||||
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
||||||
));
|
));
|
||||||
return Center(
|
return Center(
|
||||||
child: NotificationListener<ScrollNotification>(
|
child: NotificationListener<ScrollNotification>(
|
||||||
onNotification: (notification) {
|
onNotification: (notification) {
|
||||||
final percentX = _horizontal.position.extentBefore /
|
final percentX = _horizontal.position.extentBefore /
|
||||||
(_horizontal.position.extentBefore +
|
(_horizontal.position.extentBefore +
|
||||||
_horizontal.position.extentInside +
|
_horizontal.position.extentInside +
|
||||||
_horizontal.position.extentAfter);
|
_horizontal.position.extentAfter);
|
||||||
final percentY = _vertical.position.extentBefore /
|
final percentY = _vertical.position.extentBefore /
|
||||||
(_vertical.position.extentBefore +
|
(_vertical.position.extentBefore +
|
||||||
_vertical.position.extentInside +
|
_vertical.position.extentInside +
|
||||||
_vertical.position.extentAfter);
|
_vertical.position.extentAfter);
|
||||||
c.setScrollPercent(percentX, percentY);
|
c.setScrollPercent(percentX, percentY);
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
child: Obx(() => MouseRegion(
|
child: Obx(() => MouseRegion(
|
||||||
cursor: cursorOverImage.value
|
cursor: (keyboardEnabled.isTrue && cursorOverImage.isTrue)
|
||||||
? SystemMouseCursors.none
|
? SystemMouseCursors.none
|
||||||
: SystemMouseCursors.basic,
|
: MouseCursor.defer,
|
||||||
child: _buildCrossScrollbar(_buildListener(imageWidget)))),
|
child: _buildCrossScrollbar(_buildListener(imageWidget)))),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
final imageWidget = SizedBox(
|
final imageWidget = SizedBox(
|
||||||
width: c.size.width,
|
width: c.size.width,
|
||||||
@ -562,13 +562,12 @@ class CursorPaint extends StatelessWidget {
|
|||||||
final m = Provider.of<CursorModel>(context);
|
final m = Provider.of<CursorModel>(context);
|
||||||
final c = Provider.of<CanvasModel>(context);
|
final c = Provider.of<CanvasModel>(context);
|
||||||
// final adjust = m.adjustForKeyboard();
|
// final adjust = m.adjustForKeyboard();
|
||||||
var s = c.scale;
|
|
||||||
return CustomPaint(
|
return CustomPaint(
|
||||||
painter: ImagePainter(
|
painter: ImagePainter(
|
||||||
image: m.image,
|
image: m.image,
|
||||||
x: m.x * s - m.hotx + c.x,
|
x: m.x - m.hotx + c.x / c.scale,
|
||||||
y: m.y * s - m.hoty + c.y,
|
y: m.y - m.hoty + c.y / c.scale,
|
||||||
scale: 1),
|
scale: c.scale),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -620,30 +619,30 @@ class QualityMonitor extends StatelessWidget {
|
|||||||
right: 10,
|
right: 10,
|
||||||
child: qualityMonitorModel.show
|
child: qualityMonitorModel.show
|
||||||
? Container(
|
? Container(
|
||||||
padding: EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
color: MyTheme.canvasColor.withAlpha(120),
|
color: MyTheme.canvasColor.withAlpha(120),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Speed: ${qualityMonitorModel.data.speed ?? ''}",
|
"Speed: ${qualityMonitorModel.data.speed ?? ''}",
|
||||||
style: TextStyle(color: MyTheme.grayBg),
|
style: const TextStyle(color: MyTheme.grayBg),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"FPS: ${qualityMonitorModel.data.fps ?? ''}",
|
"FPS: ${qualityMonitorModel.data.fps ?? ''}",
|
||||||
style: TextStyle(color: MyTheme.grayBg),
|
style: const TextStyle(color: MyTheme.grayBg),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Delay: ${qualityMonitorModel.data.delay ?? ''} ms",
|
"Delay: ${qualityMonitorModel.data.delay ?? ''} ms",
|
||||||
style: TextStyle(color: MyTheme.grayBg),
|
style: const TextStyle(color: MyTheme.grayBg),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Target Bitrate: ${qualityMonitorModel.data.targetBitrate ?? ''}kb",
|
"Target Bitrate: ${qualityMonitorModel.data.targetBitrate ?? ''}kb",
|
||||||
style: TextStyle(color: MyTheme.grayBg),
|
style: const TextStyle(color: MyTheme.grayBg),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Codec: ${qualityMonitorModel.data.codecFormat ?? ''}",
|
"Codec: ${qualityMonitorModel.data.codecFormat ?? ''}",
|
||||||
style: TextStyle(color: MyTheme.grayBg),
|
style: const TextStyle(color: MyTheme.grayBg),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -522,16 +522,19 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
MenuEntryDivider<String>(),
|
MenuEntryDivider<String>(),
|
||||||
MenuEntrySwitch<String>(
|
() {
|
||||||
text: translate('Show remote cursor'),
|
final state = ShowRemoteCursorState.find(widget.id);
|
||||||
getter: () async {
|
return MenuEntrySwitch2<String>(
|
||||||
return bind.sessionGetToggleOptionSync(
|
text: translate('Show remote cursor'),
|
||||||
id: widget.id, arg: 'show-remote-cursor');
|
getter: () {
|
||||||
},
|
return state;
|
||||||
setter: (bool v) async {
|
},
|
||||||
await bind.sessionToggleOption(
|
setter: (bool v) async {
|
||||||
id: widget.id, value: 'show-remote-cursor');
|
state.value = v;
|
||||||
}),
|
await bind.sessionToggleOption(
|
||||||
|
id: widget.id, value: 'show-remote-cursor');
|
||||||
|
});
|
||||||
|
}(),
|
||||||
MenuEntrySwitch<String>(
|
MenuEntrySwitch<String>(
|
||||||
text: translate('Show quality monitor'),
|
text: translate('Show quality monitor'),
|
||||||
getter: () async {
|
getter: () async {
|
||||||
@ -560,12 +563,12 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
'Lock after session end', 'lock-after-session-end'));
|
'Lock after session end', 'lock-after-session-end'));
|
||||||
if (pi.platform == 'Windows') {
|
if (pi.platform == 'Windows') {
|
||||||
displayMenu.add(MenuEntrySwitch2<String>(
|
displayMenu.add(MenuEntrySwitch2<String>(
|
||||||
|
dismissOnClicked: true,
|
||||||
text: translate('Privacy mode'),
|
text: translate('Privacy mode'),
|
||||||
getter: () {
|
getter: () {
|
||||||
return PrivacyModeState.find(widget.id);
|
return PrivacyModeState.find(widget.id);
|
||||||
},
|
},
|
||||||
setter: (bool v) async {
|
setter: (bool v) async {
|
||||||
Navigator.pop(context);
|
|
||||||
await bind.sessionToggleOption(
|
await bind.sessionToggleOption(
|
||||||
id: widget.id, value: 'privacy-mode');
|
id: widget.id, value: 'privacy-mode');
|
||||||
}));
|
}));
|
||||||
|
@ -32,7 +32,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
Display _display = Display();
|
Display _display = Display();
|
||||||
|
|
||||||
var _inputBlocked = false;
|
var _inputBlocked = false;
|
||||||
final _permissions = Map<String, bool>();
|
final _permissions = <String, bool>{};
|
||||||
bool? _secure;
|
bool? _secure;
|
||||||
bool? _direct;
|
bool? _direct;
|
||||||
bool _touchMode = false;
|
bool _touchMode = false;
|
||||||
@ -71,12 +71,13 @@ class FfiModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePermission(Map<String, dynamic> evt) {
|
void updatePermission(Map<String, dynamic> evt, String id) {
|
||||||
evt.forEach((k, v) {
|
evt.forEach((k, v) {
|
||||||
if (k == 'name' || k.isEmpty) return;
|
if (k == 'name' || k.isEmpty) return;
|
||||||
_permissions[k] = v == 'true';
|
_permissions[k] = v == 'true';
|
||||||
});
|
});
|
||||||
print('$_permissions');
|
KeyboardEnabledState.find(id).value = _permissions['keyboard'] != false;
|
||||||
|
debugPrint('$_permissions');
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
} else if (name == 'clipboard') {
|
} else if (name == 'clipboard') {
|
||||||
Clipboard.setData(ClipboardData(text: evt['content']));
|
Clipboard.setData(ClipboardData(text: evt['content']));
|
||||||
} else if (name == 'permission') {
|
} else if (name == 'permission') {
|
||||||
parent.target?.ffiModel.updatePermission(evt);
|
parent.target?.ffiModel.updatePermission(evt, peerId);
|
||||||
} else if (name == 'chat_client_mode') {
|
} else if (name == 'chat_client_mode') {
|
||||||
parent.target?.chatModel
|
parent.target?.chatModel
|
||||||
.receive(ChatModel.clientModeID, evt['text'] ?? "");
|
.receive(ChatModel.clientModeID, evt['text'] ?? "");
|
||||||
@ -185,7 +186,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
|
|
||||||
/// Bind the event listener to receive events from the Rust core.
|
/// Bind the event listener to receive events from the Rust core.
|
||||||
void updateEventListener(String peerId) {
|
void updateEventListener(String peerId) {
|
||||||
final void Function(Map<String, dynamic>) cb = (evt) {
|
cb(evt) {
|
||||||
var name = evt['name'];
|
var name = evt['name'];
|
||||||
if (name == 'msgbox') {
|
if (name == 'msgbox') {
|
||||||
handleMsgBox(evt, peerId);
|
handleMsgBox(evt, peerId);
|
||||||
@ -205,7 +206,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
} else if (name == 'clipboard') {
|
} else if (name == 'clipboard') {
|
||||||
Clipboard.setData(ClipboardData(text: evt['content']));
|
Clipboard.setData(ClipboardData(text: evt['content']));
|
||||||
} else if (name == 'permission') {
|
} else if (name == 'permission') {
|
||||||
parent.target?.ffiModel.updatePermission(evt);
|
parent.target?.ffiModel.updatePermission(evt, peerId);
|
||||||
} else if (name == 'chat_client_mode') {
|
} else if (name == 'chat_client_mode') {
|
||||||
parent.target?.chatModel
|
parent.target?.chatModel
|
||||||
.receive(ChatModel.clientModeID, evt['text'] ?? "");
|
.receive(ChatModel.clientModeID, evt['text'] ?? "");
|
||||||
@ -239,7 +240,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
} else if (name == 'update_privacy_mode') {
|
} else if (name == 'update_privacy_mode') {
|
||||||
updatePrivacyMode(evt, peerId);
|
updatePrivacyMode(evt, peerId);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
platformFFI.setEventCallback(cb);
|
platformFFI.setEventCallback(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +323,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
if (isPeerAndroid) {
|
if (isPeerAndroid) {
|
||||||
_touchMode = true;
|
_touchMode = true;
|
||||||
if (parent.target?.ffiModel.permissions['keyboard'] != false) {
|
if (parent.target?.ffiModel.permissions['keyboard'] != false) {
|
||||||
Timer(Duration(milliseconds: 100), showMobileActionsOverlay);
|
Timer(const Duration(milliseconds: 100), showMobileActionsOverlay);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_touchMode =
|
_touchMode =
|
||||||
@ -464,15 +466,20 @@ enum ScrollStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CanvasModel with ChangeNotifier {
|
class CanvasModel with ChangeNotifier {
|
||||||
|
// image offset of canvas
|
||||||
|
double _x = 0;
|
||||||
|
// image offset of canvas
|
||||||
|
double _y = 0;
|
||||||
|
// image scale
|
||||||
|
double _scale = 1.0;
|
||||||
|
// the tabbar over the image
|
||||||
|
double tabBarHeight = 0.0;
|
||||||
|
// TODO multi canvas model
|
||||||
|
String id = "";
|
||||||
// scroll offset x percent
|
// scroll offset x percent
|
||||||
double _scrollX = 0.0;
|
double _scrollX = 0.0;
|
||||||
// scroll offset y percent
|
// scroll offset y percent
|
||||||
double _scrollY = 0.0;
|
double _scrollY = 0.0;
|
||||||
double _x = 0;
|
|
||||||
double _y = 0;
|
|
||||||
double _scale = 1.0;
|
|
||||||
double _tabBarHeight = 0.0;
|
|
||||||
String id = ""; // TODO multi canvas model
|
|
||||||
ScrollStyle _scrollStyle = ScrollStyle.scrollauto;
|
ScrollStyle _scrollStyle = ScrollStyle.scrollauto;
|
||||||
|
|
||||||
WeakReference<FFI> parent;
|
WeakReference<FFI> parent;
|
||||||
@ -492,9 +499,6 @@ class CanvasModel with ChangeNotifier {
|
|||||||
double get scrollX => _scrollX;
|
double get scrollX => _scrollX;
|
||||||
double get scrollY => _scrollY;
|
double get scrollY => _scrollY;
|
||||||
|
|
||||||
set tabBarHeight(double h) => _tabBarHeight = h;
|
|
||||||
double get tabBarHeight => _tabBarHeight;
|
|
||||||
|
|
||||||
void updateViewStyle() async {
|
void updateViewStyle() async {
|
||||||
final style = await bind.sessionGetOption(id: id, arg: 'view-style');
|
final style = await bind.sessionGetOption(id: id, arg: 'view-style');
|
||||||
if (style == null) {
|
if (style == null) {
|
||||||
@ -548,12 +552,11 @@ class CanvasModel with ChangeNotifier {
|
|||||||
|
|
||||||
Size get size {
|
Size get size {
|
||||||
final size = MediaQueryData.fromWindow(ui.window).size;
|
final size = MediaQueryData.fromWindow(ui.window).size;
|
||||||
return Size(size.width, size.height - _tabBarHeight);
|
return Size(size.width, size.height - tabBarHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveDesktopMouse(double x, double y) {
|
void moveDesktopMouse(double x, double y) {
|
||||||
// On mobile platforms, move the canvas with the cursor.
|
// On mobile platforms, move the canvas with the cursor.
|
||||||
//if (!isDesktop) {
|
|
||||||
final dw = getDisplayWidth() * _scale;
|
final dw = getDisplayWidth() * _scale;
|
||||||
final dh = getDisplayHeight() * _scale;
|
final dh = getDisplayHeight() * _scale;
|
||||||
var dxOffset = 0;
|
var dxOffset = 0;
|
||||||
@ -579,8 +582,13 @@ class CanvasModel with ChangeNotifier {
|
|||||||
if (dxOffset != 0 || dyOffset != 0) {
|
if (dxOffset != 0 || dyOffset != 0) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
parent.target?.cursorModel.moveLocal(x, y);
|
// If keyboard is not permitted, do not move cursor when mouse is moving.
|
||||||
|
if (parent.target != null) {
|
||||||
|
if (parent.target!.ffiModel.keyboard()) {
|
||||||
|
parent.target!.cursorModel.moveLocal(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set scale(v) {
|
set scale(v) {
|
||||||
@ -597,11 +605,8 @@ class CanvasModel with ChangeNotifier {
|
|||||||
if (isWebDesktop) {
|
if (isWebDesktop) {
|
||||||
updateViewStyle();
|
updateViewStyle();
|
||||||
} else {
|
} else {
|
||||||
final size = MediaQueryData.fromWindow(ui.window).size;
|
_x = (size.width - getDisplayWidth() * _scale) / 2;
|
||||||
final canvasWidth = size.width;
|
_y = (size.height - getDisplayHeight() * _scale) / 2;
|
||||||
final canvasHeight = size.height - _tabBarHeight;
|
|
||||||
_x = (canvasWidth - getDisplayWidth() * _scale) / 2;
|
|
||||||
_y = (canvasHeight - getDisplayHeight() * _scale) / 2;
|
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@ -613,7 +618,7 @@ class CanvasModel with ChangeNotifier {
|
|||||||
|
|
||||||
void updateScale(double v) {
|
void updateScale(double v) {
|
||||||
if (parent.target?.imageModel.image == null) return;
|
if (parent.target?.imageModel.image == null) return;
|
||||||
final offset = parent.target?.cursorModel.offset ?? Offset(0, 0);
|
final offset = parent.target?.cursorModel.offset ?? const Offset(0, 0);
|
||||||
var r = parent.target?.cursorModel.getVisibleRect() ?? Rect.zero;
|
var r = parent.target?.cursorModel.getVisibleRect() ?? Rect.zero;
|
||||||
final px0 = (offset.dx - r.left) * _scale;
|
final px0 = (offset.dx - r.left) * _scale;
|
||||||
final py0 = (offset.dy - r.top) * _scale;
|
final py0 = (offset.dy - r.top) * _scale;
|
||||||
@ -640,7 +645,7 @@ class CanvasModel with ChangeNotifier {
|
|||||||
|
|
||||||
class CursorModel with ChangeNotifier {
|
class CursorModel with ChangeNotifier {
|
||||||
ui.Image? _image;
|
ui.Image? _image;
|
||||||
final _images = Map<int, Tuple3<ui.Image, double, double>>();
|
final _images = <int, Tuple3<ui.Image, double, double>>{};
|
||||||
double _x = -10000;
|
double _x = -10000;
|
||||||
double _y = -10000;
|
double _y = -10000;
|
||||||
double _hotx = 0;
|
double _hotx = 0;
|
||||||
@ -807,7 +812,7 @@ class CursorModel with ChangeNotifier {
|
|||||||
// my throw exception, because the listener maybe already dispose
|
// my throw exception, because the listener maybe already dispose
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('notify cursor: $e');
|
debugPrint('notify cursor: $e');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user