Merge pull request #1693 from fufesou/flutter_remote_adjust_window
Flutter remote adjust window
This commit is contained in:
commit
b5809f1315
@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:back_button_interceptor/back_button_interceptor.dart';
|
import 'package:back_button_interceptor/back_button_interceptor.dart';
|
||||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
@ -15,6 +16,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:window_size/window_size.dart' as window_size;
|
||||||
|
|
||||||
import 'common/widgets/overlay.dart';
|
import 'common/widgets/overlay.dart';
|
||||||
import 'mobile/pages/file_manager_page.dart';
|
import 'mobile/pages/file_manager_page.dart';
|
||||||
@ -23,6 +25,8 @@ import 'models/input_model.dart';
|
|||||||
import 'models/model.dart';
|
import 'models/model.dart';
|
||||||
import 'models/platform_model.dart';
|
import 'models/platform_model.dart';
|
||||||
|
|
||||||
|
import '../consts.dart';
|
||||||
|
|
||||||
final globalKey = GlobalKey<NavigatorState>();
|
final globalKey = GlobalKey<NavigatorState>();
|
||||||
final navigationBarKey = GlobalKey();
|
final navigationBarKey = GlobalKey();
|
||||||
|
|
||||||
@ -1022,6 +1026,89 @@ Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_adjustRestoreMainWindowSize(double? width, double? height) async {
|
||||||
|
const double minWidth = 600;
|
||||||
|
const double minHeight = 100;
|
||||||
|
double maxWidth = (((isDesktop || isWebDesktop)
|
||||||
|
? kDesktopMaxDisplayWidth
|
||||||
|
: kMobileMaxDisplayWidth))
|
||||||
|
.toDouble();
|
||||||
|
double maxHeight = ((isDesktop || isWebDesktop)
|
||||||
|
? kDesktopMaxDisplayHeight
|
||||||
|
: kMobileMaxDisplayHeight)
|
||||||
|
.toDouble();
|
||||||
|
|
||||||
|
if (isDesktop || isWebDesktop) {
|
||||||
|
final screen = (await window_size.getWindowInfo()).screen;
|
||||||
|
if (screen != null) {
|
||||||
|
maxWidth = screen.visibleFrame.width;
|
||||||
|
maxHeight = screen.visibleFrame.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final defaultWidth =
|
||||||
|
((isDesktop || isWebDesktop) ? 1280 : kMobileDefaultDisplayWidth)
|
||||||
|
.toDouble();
|
||||||
|
final defaultHeight =
|
||||||
|
((isDesktop || isWebDesktop) ? 720 : kMobileDefaultDisplayHeight)
|
||||||
|
.toDouble();
|
||||||
|
double restoreWidth = width ?? defaultWidth;
|
||||||
|
double restoreHeight = height ?? defaultHeight;
|
||||||
|
|
||||||
|
if (restoreWidth < minWidth) {
|
||||||
|
restoreWidth = minWidth;
|
||||||
|
}
|
||||||
|
if (restoreHeight < minHeight) {
|
||||||
|
restoreHeight = minHeight;
|
||||||
|
}
|
||||||
|
if (restoreWidth > maxWidth) {
|
||||||
|
restoreWidth = maxWidth;
|
||||||
|
}
|
||||||
|
if (restoreHeight > maxHeight) {
|
||||||
|
restoreWidth = maxHeight;
|
||||||
|
}
|
||||||
|
await windowManager.setSize(Size(restoreWidth, restoreHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
_adjustRestoreMainWindowOffset(double? left, double? top) async {
|
||||||
|
if (left == null || top == null) {
|
||||||
|
await windowManager.center();
|
||||||
|
} else {
|
||||||
|
double windowLeft = left;
|
||||||
|
double windowTop = top;
|
||||||
|
|
||||||
|
double frameLeft = 0;
|
||||||
|
double frameTop = 0;
|
||||||
|
double frameRight = ((isDesktop || isWebDesktop)
|
||||||
|
? kDesktopMaxDisplayWidth
|
||||||
|
: kMobileMaxDisplayWidth)
|
||||||
|
.toDouble();
|
||||||
|
double frameBottom = ((isDesktop || isWebDesktop)
|
||||||
|
? kDesktopMaxDisplayHeight
|
||||||
|
: kMobileMaxDisplayHeight)
|
||||||
|
.toDouble();
|
||||||
|
|
||||||
|
if (isDesktop || isWebDesktop) {
|
||||||
|
final screen = (await window_size.getWindowInfo()).screen;
|
||||||
|
if (screen != null) {
|
||||||
|
frameLeft = screen.visibleFrame.left;
|
||||||
|
frameTop = screen.visibleFrame.top;
|
||||||
|
frameRight = screen.visibleFrame.right;
|
||||||
|
frameBottom = screen.visibleFrame.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowLeft < frameLeft ||
|
||||||
|
windowLeft > frameRight ||
|
||||||
|
windowTop < frameTop ||
|
||||||
|
windowTop > frameBottom) {
|
||||||
|
await windowManager.center();
|
||||||
|
} else {
|
||||||
|
await windowManager.setPosition(Offset(windowLeft, windowTop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Save window position and size on exit
|
/// Save window position and size on exit
|
||||||
/// Note that windowId must be provided if it's subwindow
|
/// Note that windowId must be provided if it's subwindow
|
||||||
Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
|
Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
|
||||||
@ -1042,13 +1129,10 @@ Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
|
|||||||
debugPrint("window position saved, but cannot be parsed");
|
debugPrint("window position saved, but cannot be parsed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await windowManager.setSize(Size(lpos.width ?? 1280, lpos.height ?? 720));
|
|
||||||
if (lpos.offsetWidth == null || lpos.offsetHeight == null) {
|
await _adjustRestoreMainWindowSize(lpos.width, lpos.height);
|
||||||
await windowManager.center();
|
await _adjustRestoreMainWindowOffset(lpos.offsetWidth, lpos.offsetHeight);
|
||||||
} else {
|
|
||||||
await windowManager
|
|
||||||
.setPosition(Offset(lpos.offsetWidth!, lpos.offsetHeight!));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
// TODO: implement subwindow
|
// TODO: implement subwindow
|
||||||
|
@ -179,3 +179,25 @@ class RemoteCursorMovedState {
|
|||||||
|
|
||||||
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
static RxBool find(String id) => Get.find<RxBool>(tag: tag(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RemoteCountState {
|
||||||
|
static String tag() => 'remote_count_';
|
||||||
|
|
||||||
|
static void init() {
|
||||||
|
final key = tag();
|
||||||
|
if (!Get.isRegistered(tag: key)) {
|
||||||
|
// Server side, default true
|
||||||
|
final RxInt state = 1.obs;
|
||||||
|
Get.put(state, tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete() {
|
||||||
|
final key = tag();
|
||||||
|
if (Get.isRegistered(tag: key)) {
|
||||||
|
Get.delete(tag: key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RxInt find() => Get.find<RxInt>(tag: tag());
|
||||||
|
}
|
||||||
|
@ -20,6 +20,12 @@ const int kMobileDefaultDisplayHeight = 1280;
|
|||||||
const int kDesktopDefaultDisplayWidth = 1080;
|
const int kDesktopDefaultDisplayWidth = 1080;
|
||||||
const int kDesktopDefaultDisplayHeight = 720;
|
const int kDesktopDefaultDisplayHeight = 720;
|
||||||
|
|
||||||
|
const int kMobileMaxDisplayWidth = 720;
|
||||||
|
const int kMobileMaxDisplayHeight = 1280;
|
||||||
|
|
||||||
|
const int kDesktopMaxDisplayWidth = 1920;
|
||||||
|
const int kDesktopMaxDisplayHeight = 1080;
|
||||||
|
|
||||||
const Size kConnectionManagerWindowSize = Size(300, 400);
|
const Size kConnectionManagerWindowSize = Size(300, 400);
|
||||||
// Tabbar transition duration, now we remove the duration
|
// Tabbar transition duration, now we remove the duration
|
||||||
const Duration kTabTransitionDuration = Duration.zero;
|
const Duration kTabTransitionDuration = Duration.zero;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart' hide MenuItem;
|
import 'package:flutter/material.dart' hide MenuItem;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -16,6 +17,7 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:tray_manager/tray_manager.dart';
|
import 'package:tray_manager/tray_manager.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:window_size/window_size.dart' as window_size;
|
||||||
|
|
||||||
import '../widgets/button.dart';
|
import '../widgets/button.dart';
|
||||||
|
|
||||||
@ -427,6 +429,27 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
|||||||
"call ${call.method} with args ${call.arguments} from window $fromWindowId");
|
"call ${call.method} with args ${call.arguments} from window $fromWindowId");
|
||||||
if (call.method == "main_window_on_top") {
|
if (call.method == "main_window_on_top") {
|
||||||
window_on_top(null);
|
window_on_top(null);
|
||||||
|
} else if (call.method == "get_window_info") {
|
||||||
|
final screen = (await window_size.getWindowInfo()).screen;
|
||||||
|
if (screen == null) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return jsonEncode({
|
||||||
|
'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,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
|
import '../../common/shared_state.dart';
|
||||||
|
|
||||||
class DesktopTabPage extends StatefulWidget {
|
class DesktopTabPage extends StatefulWidget {
|
||||||
const DesktopTabPage({Key? key}) : super(key: key);
|
const DesktopTabPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@ -40,6 +42,7 @@ class _DesktopTabPageState extends State<DesktopTabPage> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
Get.put<DesktopTabController>(tabController);
|
Get.put<DesktopTabController>(tabController);
|
||||||
|
RemoteCountState.init();
|
||||||
tabController.add(TabInfo(
|
tabController.add(TabInfo(
|
||||||
key: kTabLabelHomePage,
|
key: kTabLabelHomePage,
|
||||||
label: kTabLabelHomePage,
|
label: kTabLabelHomePage,
|
||||||
|
@ -28,11 +28,13 @@ class RemotePage extends StatefulWidget {
|
|||||||
const RemotePage({
|
const RemotePage({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.id,
|
required this.id,
|
||||||
|
required this.windowId,
|
||||||
required this.tabBarHeight,
|
required this.tabBarHeight,
|
||||||
required this.windowBorderWidth,
|
required this.windowBorderWidth,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
|
final int windowId;
|
||||||
final double tabBarHeight;
|
final double tabBarHeight;
|
||||||
final double windowBorderWidth;
|
final double windowBorderWidth;
|
||||||
|
|
||||||
@ -239,6 +241,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
paints.add(QualityMonitor(_ffi.qualityMonitorModel));
|
paints.add(QualityMonitor(_ffi.qualityMonitorModel));
|
||||||
paints.add(RemoteMenubar(
|
paints.add(RemoteMenubar(
|
||||||
id: widget.id,
|
id: widget.id,
|
||||||
|
windowId: widget.windowId,
|
||||||
ffi: _ffi,
|
ffi: _ffi,
|
||||||
onEnterOrLeaveImageSetter: (func) => _onEnterOrLeaveImage4Menubar = func,
|
onEnterOrLeaveImageSetter: (func) => _onEnterOrLeaveImage4Menubar = func,
|
||||||
onEnterOrLeaveImageCleaner: () => _onEnterOrLeaveImage4Menubar = null,
|
onEnterOrLeaveImageCleaner: () => _onEnterOrLeaveImage4Menubar = null,
|
||||||
|
@ -32,6 +32,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
var connectionMap = RxList<Widget>.empty(growable: true);
|
var connectionMap = RxList<Widget>.empty(growable: true);
|
||||||
|
|
||||||
_ConnectionTabPageState(Map<String, dynamic> params) {
|
_ConnectionTabPageState(Map<String, dynamic> params) {
|
||||||
|
RemoteCountState.init();
|
||||||
final RxBool fullscreen = Get.find(tag: 'fullscreen');
|
final RxBool fullscreen = Get.find(tag: 'fullscreen');
|
||||||
final peerId = params['id'];
|
final peerId = params['id'];
|
||||||
if (peerId != null) {
|
if (peerId != null) {
|
||||||
@ -45,10 +46,12 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
page: Obx(() => RemotePage(
|
page: Obx(() => RemotePage(
|
||||||
key: ValueKey(peerId),
|
key: ValueKey(peerId),
|
||||||
id: peerId,
|
id: peerId,
|
||||||
|
windowId: windowId(),
|
||||||
tabBarHeight:
|
tabBarHeight:
|
||||||
fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight,
|
fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight,
|
||||||
windowBorderWidth: fullscreen.isTrue ? 0 : kWindowBorderWidth,
|
windowBorderWidth: fullscreen.isTrue ? 0 : kWindowBorderWidth,
|
||||||
))));
|
))));
|
||||||
|
_update_remote_count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +82,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
page: Obx(() => RemotePage(
|
page: Obx(() => RemotePage(
|
||||||
key: ValueKey(id),
|
key: ValueKey(id),
|
||||||
id: id,
|
id: id,
|
||||||
|
windowId: windowId(),
|
||||||
tabBarHeight:
|
tabBarHeight:
|
||||||
fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight,
|
fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight,
|
||||||
windowBorderWidth: fullscreen.isTrue ? 0 : kWindowBorderWidth,
|
windowBorderWidth: fullscreen.isTrue ? 0 : kWindowBorderWidth,
|
||||||
@ -86,6 +90,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
} else if (call.method == "onDestroy") {
|
} else if (call.method == "onDestroy") {
|
||||||
tabController.clear();
|
tabController.clear();
|
||||||
}
|
}
|
||||||
|
_update_remote_count();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +166,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
WindowController.fromWindowId(windowId()).hide();
|
WindowController.fromWindowId(windowId()).hide();
|
||||||
}
|
}
|
||||||
ConnectionTypeState.delete(id);
|
ConnectionTypeState.delete(id);
|
||||||
|
_update_remote_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
int windowId() {
|
int windowId() {
|
||||||
@ -178,7 +184,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> handleWindowCloseButton() async {
|
Future<bool> handleWindowCloseButton() async {
|
||||||
final connLength = tabController.state.value.tabs.length;
|
final connLength = tabController.length;
|
||||||
if (connLength < 1) {
|
if (connLength < 1) {
|
||||||
return true;
|
return true;
|
||||||
} else if (connLength == 1) {
|
} else if (connLength == 1) {
|
||||||
@ -189,8 +195,12 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
final res = await closeConfirmDialog();
|
final res = await closeConfirmDialog();
|
||||||
if (res) {
|
if (res) {
|
||||||
tabController.clear();
|
tabController.clear();
|
||||||
|
_update_remote_count();
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_update_remote_count() =>
|
||||||
|
RemoteCountState.find().value = tabController.length;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
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';
|
||||||
@ -8,6 +9,8 @@ import 'package:flutter_hbb/models/chat_model.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;
|
||||||
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
|
import 'package:window_size/window_size.dart' as window_size;
|
||||||
|
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../mobile/widgets/dialog.dart';
|
import '../../mobile/widgets/dialog.dart';
|
||||||
@ -26,6 +29,7 @@ class _MenubarTheme {
|
|||||||
|
|
||||||
class RemoteMenubar extends StatefulWidget {
|
class RemoteMenubar extends StatefulWidget {
|
||||||
final String id;
|
final String id;
|
||||||
|
final int windowId;
|
||||||
final FFI ffi;
|
final FFI ffi;
|
||||||
final Function(Function(bool)) onEnterOrLeaveImageSetter;
|
final Function(Function(bool)) onEnterOrLeaveImageSetter;
|
||||||
final Function() onEnterOrLeaveImageCleaner;
|
final Function() onEnterOrLeaveImageCleaner;
|
||||||
@ -33,6 +37,7 @@ class RemoteMenubar extends StatefulWidget {
|
|||||||
const RemoteMenubar({
|
const RemoteMenubar({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.id,
|
required this.id,
|
||||||
|
required this.windowId,
|
||||||
required this.ffi,
|
required this.ffi,
|
||||||
required this.onEnterOrLeaveImageSetter,
|
required this.onEnterOrLeaveImageSetter,
|
||||||
required this.onEnterOrLeaveImageCleaner,
|
required this.onEnterOrLeaveImageCleaner,
|
||||||
@ -48,6 +53,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
final _rxHideReplay = rxdart.ReplaySubject<int>();
|
final _rxHideReplay = rxdart.ReplaySubject<int>();
|
||||||
final _pinMenubar = false.obs;
|
final _pinMenubar = false.obs;
|
||||||
bool _isCursorOverImage = false;
|
bool _isCursorOverImage = false;
|
||||||
|
window_size.Screen? _screen;
|
||||||
|
|
||||||
bool get isFullscreen => Get.find<RxBool>(tag: 'fullscreen').isTrue;
|
bool get isFullscreen => Get.find<RxBool>(tag: 'fullscreen').isTrue;
|
||||||
void _setFullscreen(bool v) {
|
void _setFullscreen(bool v) {
|
||||||
@ -105,12 +111,34 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
},
|
},
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_show.value = !_show.value;
|
_show.value = !_show.value;
|
||||||
|
if (_show.isTrue) {
|
||||||
|
_updateScreen();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Obx(() => Container(
|
child: Obx(() => Container(
|
||||||
color: _hideColor.value,
|
color: _hideColor.value,
|
||||||
).marginOnly(bottom: 8.0))))));
|
).marginOnly(bottom: 8.0))))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateScreen() async {
|
||||||
|
final v = await DesktopMultiWindow.invokeMethod(0, "get_window_info", "");
|
||||||
|
final String valueStr = v;
|
||||||
|
if (valueStr.isEmpty) {
|
||||||
|
_screen = null;
|
||||||
|
} else {
|
||||||
|
final screenMap = jsonDecode(valueStr);
|
||||||
|
_screen = window_size.Screen(
|
||||||
|
Rect.fromLTRB(screenMap['frame']['l'], screenMap['frame']['t'],
|
||||||
|
screenMap['frame']['r'], screenMap['frame']['b']),
|
||||||
|
Rect.fromLTRB(
|
||||||
|
screenMap['visibleFrame']['l'],
|
||||||
|
screenMap['visibleFrame']['t'],
|
||||||
|
screenMap['visibleFrame']['r'],
|
||||||
|
screenMap['visibleFrame']['b']),
|
||||||
|
screenMap['scaleFactor']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildMenubar(BuildContext context) {
|
Widget _buildMenubar(BuildContext context) {
|
||||||
final List<Widget> menubarItems = [];
|
final List<Widget> menubarItems = [];
|
||||||
if (!isWebDesktop) {
|
if (!isWebDesktop) {
|
||||||
@ -306,25 +334,29 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
return {'supportedHwcodec': supportedHwcodec};
|
return {'supportedHwcodec': supportedHwcodec};
|
||||||
}(), builder: (context, snapshot) {
|
}(), builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
return mod_menu.PopupMenuButton(
|
return Obx(() {
|
||||||
padding: EdgeInsets.zero,
|
final remoteCount = RemoteCountState.find().value;
|
||||||
icon: const Icon(
|
return mod_menu.PopupMenuButton(
|
||||||
Icons.tv,
|
padding: EdgeInsets.zero,
|
||||||
color: _MenubarTheme.commonColor,
|
icon: const Icon(
|
||||||
),
|
Icons.tv,
|
||||||
tooltip: translate('Display Settings'),
|
color: _MenubarTheme.commonColor,
|
||||||
position: mod_menu.PopupMenuPosition.under,
|
),
|
||||||
itemBuilder: (BuildContext context) => _getDisplayMenu(snapshot.data!)
|
tooltip: translate('Display Settings'),
|
||||||
.map((entry) => entry.build(
|
position: mod_menu.PopupMenuPosition.under,
|
||||||
context,
|
itemBuilder: (BuildContext context) =>
|
||||||
const MenuConfig(
|
_getDisplayMenu(snapshot.data!, remoteCount)
|
||||||
commonColor: _MenubarTheme.commonColor,
|
.map((entry) => entry.build(
|
||||||
height: _MenubarTheme.height,
|
context,
|
||||||
dividerHeight: _MenubarTheme.dividerHeight,
|
const MenuConfig(
|
||||||
)))
|
commonColor: _MenubarTheme.commonColor,
|
||||||
.expand((i) => i)
|
height: _MenubarTheme.height,
|
||||||
.toList(),
|
dividerHeight: _MenubarTheme.dividerHeight,
|
||||||
);
|
)))
|
||||||
|
.expand((i) => i)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return const Offstage();
|
return const Offstage();
|
||||||
}
|
}
|
||||||
@ -586,7 +618,34 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
return displayMenu;
|
return displayMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MenuEntryBase<String>> _getDisplayMenu(dynamic futureData) {
|
bool _isWindowCanBeAdjusted(int remoteCount) {
|
||||||
|
if (remoteCount != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_screen == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double scale = _screen!.scaleFactor;
|
||||||
|
double selfWidth = _screen!.frame.width;
|
||||||
|
double selfHeight = _screen!.frame.height;
|
||||||
|
if (isFullscreen) {
|
||||||
|
selfWidth = _screen!.visibleFrame.width;
|
||||||
|
selfHeight = _screen!.visibleFrame.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
final canvasModel = widget.ffi.canvasModel;
|
||||||
|
final displayWidth = canvasModel.getDisplayWidth();
|
||||||
|
final displayHeight = canvasModel.getDisplayHeight();
|
||||||
|
final requiredWidth = displayWidth +
|
||||||
|
(canvasModel.tabBarHeight + canvasModel.windowBorderWidth * 2);
|
||||||
|
final requiredHeight = displayHeight +
|
||||||
|
(canvasModel.tabBarHeight + canvasModel.windowBorderWidth * 2);
|
||||||
|
return selfWidth > (requiredWidth * scale) &&
|
||||||
|
selfHeight > (requiredHeight * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MenuEntryBase<String>> _getDisplayMenu(
|
||||||
|
dynamic futureData, int remoteCount) {
|
||||||
const EdgeInsets padding = EdgeInsets.only(left: 18.0, right: 8.0);
|
const EdgeInsets padding = EdgeInsets.only(left: 18.0, right: 8.0);
|
||||||
final displayMenu = [
|
final displayMenu = [
|
||||||
MenuEntryRadios<String>(
|
MenuEntryRadios<String>(
|
||||||
@ -739,6 +798,77 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
MenuEntryDivider<String>(),
|
MenuEntryDivider<String>(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (_isWindowCanBeAdjusted(remoteCount)) {
|
||||||
|
displayMenu.insert(
|
||||||
|
0,
|
||||||
|
MenuEntryDivider<String>(),
|
||||||
|
);
|
||||||
|
displayMenu.insert(
|
||||||
|
0,
|
||||||
|
MenuEntryButton<String>(
|
||||||
|
childBuilder: (TextStyle? style) => Container(
|
||||||
|
child: Text(
|
||||||
|
translate('Adjust Window'),
|
||||||
|
style: style,
|
||||||
|
)),
|
||||||
|
proc: () {
|
||||||
|
() async {
|
||||||
|
await _updateScreen();
|
||||||
|
if (_screen != null) {
|
||||||
|
_setFullscreen(false);
|
||||||
|
double scale = _screen!.scaleFactor;
|
||||||
|
final wndRect =
|
||||||
|
await WindowController.fromWindowId(widget.windowId)
|
||||||
|
.getFrame();
|
||||||
|
final mediaSize = MediaQueryData.fromWindow(ui.window).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 = widget.ffi.canvasModel;
|
||||||
|
final width = (canvasModel.getDisplayWidth() +
|
||||||
|
canvasModel.windowBorderWidth * 2) *
|
||||||
|
scale +
|
||||||
|
magicWidth;
|
||||||
|
final height = (canvasModel.getDisplayHeight() +
|
||||||
|
canvasModel.tabBarHeight +
|
||||||
|
canvasModel.windowBorderWidth * 2) *
|
||||||
|
scale +
|
||||||
|
magicHeight;
|
||||||
|
double left = wndRect.left + (wndRect.width - width) / 2;
|
||||||
|
double top = wndRect.top + (wndRect.height - height) / 2;
|
||||||
|
|
||||||
|
Rect frameRect = _screen!.frame;
|
||||||
|
final RxBool fullscreen = Get.find(tag: 'fullscreen');
|
||||||
|
if (fullscreen.isFalse) {
|
||||||
|
frameRect = _screen!.visibleFrame;
|
||||||
|
}
|
||||||
|
if (left < frameRect.left) {
|
||||||
|
left = frameRect.left;
|
||||||
|
}
|
||||||
|
if (top < frameRect.top) {
|
||||||
|
top = frameRect.top;
|
||||||
|
}
|
||||||
|
if ((left + width) > frameRect.right) {
|
||||||
|
left = frameRect.right - width;
|
||||||
|
}
|
||||||
|
if ((top + height) > frameRect.bottom) {
|
||||||
|
top = frameRect.bottom - height;
|
||||||
|
}
|
||||||
|
await WindowController.fromWindowId(widget.windowId)
|
||||||
|
.setFrame(Rect.fromLTWH(left, top, width, height));
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
},
|
||||||
|
padding: padding,
|
||||||
|
dismissOnClicked: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Show Codec Preference
|
/// Show Codec Preference
|
||||||
if (bind.mainHasHwcodec()) {
|
if (bind.mainHasHwcodec()) {
|
||||||
final List<bool> codecs = [];
|
final List<bool> codecs = [];
|
||||||
|
@ -69,6 +69,8 @@ class DesktopTabController {
|
|||||||
|
|
||||||
DesktopTabController({required this.tabType});
|
DesktopTabController({required this.tabType});
|
||||||
|
|
||||||
|
int get length => state.value.tabs.length;
|
||||||
|
|
||||||
void add(TabInfo tab, {bool authorized = false}) {
|
void add(TabInfo tab, {bool authorized = false}) {
|
||||||
if (!isDesktop) return;
|
if (!isDesktop) return;
|
||||||
final index = state.value.tabs.indexWhere((e) => e.key == tab.key);
|
final index = state.value.tabs.indexWhere((e) => e.key == tab.key);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -73,7 +73,12 @@ dependencies:
|
|||||||
flutter_custom_cursor:
|
flutter_custom_cursor:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Kingtous/rustdesk_flutter_custom_cursor
|
url: https://github.com/Kingtous/rustdesk_flutter_custom_cursor
|
||||||
ref: 4a950fd3a5a228bf5381070a4c803919d5787c07
|
ref: 4a950fd3a5a228bf5381070a4c803919d5787c07
|
||||||
|
window_size:
|
||||||
|
git:
|
||||||
|
url: https://github.com/google/flutter-desktop-embedding.git
|
||||||
|
path: plugins/window_size
|
||||||
|
ref: a738913c8ce2c9f47515382d40827e794a334274
|
||||||
get: ^4.6.5
|
get: ^4.6.5
|
||||||
visibility_detector: ^0.3.3
|
visibility_detector: ^0.3.3
|
||||||
contextmenu: ^3.0.0
|
contextmenu: ^3.0.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user