Merge pull request #5166 from dignow/feat/minimize_on_fullscreen

add minimize button on fullscreen toolbar
This commit is contained in:
RustDesk 2023-07-30 19:23:26 +08:00 committed by GitHub
commit 2ab513893d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 58 deletions

View File

@ -1398,6 +1398,17 @@ Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
isMaximized = await wc.isMaximized();
break;
}
if (Platform.isWindows) {
const kMinOffset = -10000;
const kMaxOffset = 10000;
if (position.dx < kMinOffset ||
position.dy < kMinOffset ||
position.dx > kMaxOffset ||
position.dy > kMaxOffset) {
debugPrint("Invalid position: $position, ignore saving position");
return;
}
}
final pos = LastWindowPosition(
sz.width, sz.height, position.dx, position.dy, isMaximized);

View File

@ -4,7 +4,6 @@ import 'dart:ui' as ui;
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/common/shared_state.dart';
import 'package:flutter_hbb/consts.dart';
@ -172,7 +171,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
connectionType.secure.value == ConnectionType.strSecure;
bool direct =
connectionType.direct.value == ConnectionType.strDirect;
var msgConn;
String msgConn;
if (secure && direct) {
msgConn = translate("Direct and encrypted connection");
} else if (secure && !direct) {

View File

@ -1,5 +1,4 @@
import 'dart:convert';
import 'dart:ui' as ui;
import 'dart:async';
import 'dart:io';
@ -360,6 +359,9 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
triggerAutoHide() => _debouncerHide.value = _debouncerHide.value + 1;
void _minimize() async =>
await WindowController.fromWindowId(windowId).minimize();
@override
initState() {
super.initState();
@ -429,6 +431,8 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
dragging: _dragging,
fractionX: _fractionX,
show: show,
setFullscreen: _setFullscreen,
setMinimize: _minimize,
),
),
),
@ -440,8 +444,6 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
final List<Widget> toolbarItems = [];
if (!isWebDesktop) {
toolbarItems.add(_PinMenu(state: widget.state));
toolbarItems.add(
_FullscreenMenu(state: widget.state, setFullscreen: _setFullscreen));
toolbarItems.add(_MobileActionMenu(ffi: widget.ffi));
}
@ -549,27 +551,6 @@ class _PinMenu extends StatelessWidget {
}
}
class _FullscreenMenu extends StatelessWidget {
final ToolbarState state;
final Function(bool) setFullscreen;
bool get isFullscreen => stateGlobal.fullscreen;
const _FullscreenMenu(
{Key? key, required this.state, required this.setFullscreen})
: super(key: key);
@override
Widget build(BuildContext context) {
return _IconMenuButton(
assetName:
isFullscreen ? "assets/fullscreen_exit.svg" : "assets/fullscreen.svg",
tooltip: isFullscreen ? 'Exit Fullscreen' : 'Fullscreen',
onPressed: () => setFullscreen(!isFullscreen),
color: _ToolbarTheme.blueColor,
hoverColor: _ToolbarTheme.hoverBlueColor,
);
}
}
class _MobileActionMenu extends StatelessWidget {
final FFI ffi;
const _MobileActionMenu({Key? key, required this.ffi}) : super(key: key);
@ -614,7 +595,7 @@ class _MonitorMenu extends StatelessWidget {
children: [
SvgPicture.asset(
"assets/screen.svg",
color: Colors.white,
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
),
Obx(() {
RxInt display = CurrentDisplayState.find(id);
@ -650,7 +631,7 @@ class _MonitorMenu extends StatelessWidget {
children: [
SvgPicture.asset(
"assets/screen.svg",
color: Colors.white,
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
),
Text(
(i + 1).toString(),
@ -721,7 +702,7 @@ class ScreenAdjustor {
bool get isFullscreen => stateGlobal.fullscreen;
int get windowId => stateGlobal.windowId;
adjustWindow() {
adjustWindow(BuildContext context) {
return futureBuilder(
future: isWindowCanBeAdjusted(),
hasData: (data) {
@ -731,7 +712,7 @@ class ScreenAdjustor {
children: [
MenuButton(
child: Text(translate('Adjust Window')),
onPressed: doAdjustWindow,
onPressed: () => doAdjustWindow(context),
ffi: ffi),
Divider(),
],
@ -739,20 +720,19 @@ class ScreenAdjustor {
});
}
doAdjustWindow() async {
doAdjustWindow(BuildContext context) async {
await updateScreen();
if (_screen != null) {
cbExitFullscreen();
double scale = _screen!.scaleFactor;
final wndRect = await WindowController.fromWindowId(windowId).getFrame();
final mediaSize = MediaQueryData.fromWindow(ui.window).size;
final mediaSize = MediaQueryData.fromView(View.of(context)).size;
// On windows, wndRect is equal to GetWindowRect and mediaSize is equal to GetClientRect.
// https://stackoverflow.com/a/7561083
double magicWidth =
wndRect.right - wndRect.left - mediaSize.width * scale;
double magicHeight =
wndRect.bottom - wndRect.top - mediaSize.height * scale;
final canvasModel = ffi.canvasModel;
final width = (canvasModel.getDisplayWidth() * canvasModel.scale +
CanvasModel.leftToEdge +
@ -895,7 +875,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
color: _ToolbarTheme.blueColor,
hoverColor: _ToolbarTheme.hoverBlueColor,
menuChildren: [
_screenAdjustor.adjustWindow(),
_screenAdjustor.adjustWindow(context),
viewStyle(),
scrollStyle(),
imageQuality(),
@ -1082,9 +1062,9 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
return _SubmenuButton(
ffi: widget.ffi,
menuChildren: <Widget>[
_OriginalResolutionMenuButton(showOriginalBtn),
_FitLocalResolutionMenuButton(showFitLocalBtn),
_customResolutionMenuButton(isVirtualDisplay),
_OriginalResolutionMenuButton(context, showOriginalBtn),
_FitLocalResolutionMenuButton(context, showFitLocalBtn),
_customResolutionMenuButton(context, isVirtualDisplay),
_menuDivider(showOriginalBtn, showFitLocalBtn, isVirtualDisplay),
] +
_supportedResolutionMenuButtons(),
@ -1125,7 +1105,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
}
}
_onChanged(String? value) async {
_onChanged(BuildContext context, String? value) async {
stateGlobal.setLastResolutionGroupValue(
widget.id, pi.currentDisplay, value);
if (value == null) return;
@ -1145,12 +1125,12 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
if (w != null && h != null) {
if (w != display.width || h != display.height) {
await _changeResolution(w, h);
await _changeResolution(context, w, h);
}
}
}
_changeResolution(int w, int h) async {
_changeResolution(BuildContext context, int w, int h) async {
await bind.sessionChangeResolution(
sessionId: ffi.sessionId,
display: pi.currentDisplay,
@ -1161,18 +1141,19 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
final display = ffiModel.display;
if (w == display.width && h == display.height) {
if (await widget.screenAdjustor.isWindowCanBeAdjusted()) {
widget.screenAdjustor.doAdjustWindow();
widget.screenAdjustor.doAdjustWindow(context);
}
}
});
}
Widget _OriginalResolutionMenuButton(bool showOriginalBtn) {
Widget _OriginalResolutionMenuButton(
BuildContext context, bool showOriginalBtn) {
return Offstage(
offstage: !showOriginalBtn,
child: MenuButton(
onPressed: () =>
_changeResolution(display.originalWidth, display.originalHeight),
onPressed: () => _changeResolution(
context, display.originalWidth, display.originalHeight),
ffi: widget.ffi,
child: Text(
'${translate('resolution_original_tip')} ${display.originalWidth}x${display.originalHeight}'),
@ -1180,14 +1161,15 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
);
}
Widget _FitLocalResolutionMenuButton(bool showFitLocalBtn) {
Widget _FitLocalResolutionMenuButton(
BuildContext context, bool showFitLocalBtn) {
return Offstage(
offstage: !showFitLocalBtn,
child: MenuButton(
onPressed: () {
final resolution = _getBestFitResolution();
if (resolution != null) {
_changeResolution(resolution.width, resolution.height);
_changeResolution(context, resolution.width, resolution.height);
}
},
ffi: widget.ffi,
@ -1197,13 +1179,13 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
);
}
Widget _customResolutionMenuButton(isVirtualDisplay) {
Widget _customResolutionMenuButton(BuildContext context, isVirtualDisplay) {
return Offstage(
offstage: !isVirtualDisplay,
child: RdoMenuButton(
value: _kCustomResolutionValue,
groupValue: _groupValue,
onChanged: _onChanged,
onChanged: (String? value) => _onChanged(context, value),
ffi: widget.ffi,
child: Row(
children: [
@ -1244,7 +1226,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
.map((e) => RdoMenuButton(
value: '${e.width}x${e.height}',
groupValue: _groupValue,
onChanged: _onChanged,
onChanged: (String? value) => _onChanged(context, value),
ffi: widget.ffi,
child: Text('${e.width}x${e.height}')))
.toList();
@ -1597,11 +1579,11 @@ class _IconMenuButtonState extends State<_IconMenuButton> {
final icon = widget.icon ??
SvgPicture.asset(
widget.assetName!,
color: Colors.white,
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
width: _ToolbarTheme.buttonSize,
height: _ToolbarTheme.buttonSize,
);
final button = SizedBox(
var button = SizedBox(
width: _ToolbarTheme.buttonSize,
height: _ToolbarTheme.buttonSize,
child: MenuItemButton(
@ -1625,6 +1607,12 @@ class _IconMenuButtonState extends State<_IconMenuButton> {
).marginSymmetric(
horizontal: widget.hMargin ?? _ToolbarTheme.buttonHMargin,
vertical: widget.vMargin ?? _ToolbarTheme.buttonVMargin);
if (widget.tooltip != null) {
button = Tooltip(
message: widget.tooltip!,
child: button,
);
}
if (widget.topLevel) {
return MenuBar(children: [button]);
} else {
@ -1668,7 +1656,7 @@ class _IconSubmenuButtonState extends State<_IconSubmenuButton> {
final icon = widget.icon ??
SvgPicture.asset(
widget.svg!,
color: Colors.white,
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),
width: _ToolbarTheme.buttonSize,
height: _ToolbarTheme.buttonSize,
);
@ -1817,12 +1805,18 @@ class _DraggableShowHide extends StatefulWidget {
final RxDouble fractionX;
final RxBool dragging;
final RxBool show;
final Function(bool) setFullscreen;
final Function() setMinimize;
const _DraggableShowHide({
Key? key,
required this.sessionId,
required this.fractionX,
required this.dragging,
required this.show,
required this.setFullscreen,
required this.setMinimize,
}) : super(key: key);
@override
@ -1876,7 +1870,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
widget.dragging.value = true;
}),
onDragEnd: (details) {
final mediaSize = MediaQueryData.fromWindow(ui.window).size;
final mediaSize = MediaQueryData.fromView(View.of(context)).size;
widget.fractionX.value +=
(details.offset.dx - position.dx) / (mediaSize.width - size.width);
if (widget.fractionX.value < left) {
@ -1901,17 +1895,49 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
minimumSize: MaterialStateProperty.all(const Size(0, 0)),
padding: MaterialStateProperty.all(EdgeInsets.zero),
);
final isFullscreen = stateGlobal.fullscreen;
const double iconSize = 20;
final child = Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildDraggable(context),
TextButton(
onPressed: () {
widget.setFullscreen(!isFullscreen);
setState(() {});
},
child: Tooltip(
message: translate(isFullscreen ? 'Exit Fullscreen' : 'Fullscreen'),
child: Icon(
isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen,
size: iconSize,
),
),
),
Offstage(
offstage: !isFullscreen,
child: TextButton(
onPressed: () => widget.setMinimize(),
child: Tooltip(
message: translate('Minimize'),
child: Icon(
Icons.remove,
size: iconSize,
),
),
),
),
TextButton(
onPressed: () => setState(() {
widget.show.value = !widget.show.value;
}),
child: Obx((() => Icon(
widget.show.isTrue ? Icons.expand_less : Icons.expand_more,
size: 20,
child: Obx((() => Tooltip(
message: translate(
widget.show.isTrue ? 'Hide Toolbar' : 'Show Toolbar'),
child: Icon(
widget.show.isTrue ? Icons.expand_less : Icons.expand_more,
size: iconSize,
),
))),
),
],
@ -1993,7 +2019,8 @@ class _MultiMonitorMenu extends StatelessWidget {
children: [
SvgPicture.asset(
"assets/screen.svg",
color: Colors.white,
colorFilter:
ColorFilter.mode(Colors.white, BlendMode.srcIn),
),
Obx(
() => Text(

View File

@ -65,7 +65,7 @@ class StateGlobal {
? kMaximizeEdgeSize
: kWindowEdgeSize;
print(
"fullscreen: ${fullscreen}, resizeEdgeSize: ${_resizeEdgeSize.value}");
"fullscreen: $fullscreen, resizeEdgeSize: ${_resizeEdgeSize.value}");
_windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth;
WindowController.fromWindowId(windowId)
.setFullscreen(_fullscreen)