refact: window frame border (#7946)
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
26adc557bf
commit
01322146c0
@ -3214,3 +3214,46 @@ Widget buildPresetPasswordWarning() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/leanflutter/window_manager/blob/87dd7a50b4cb47a375b9fc697f05e56eea0a2ab3/lib/src/widgets/virtual_window_frame.dart#L44
|
||||||
|
Widget buildVirtualWindowFrame(BuildContext context, Widget child) {
|
||||||
|
boxShadow() => isMainDesktopWindow
|
||||||
|
? <BoxShadow>[
|
||||||
|
if (stateGlobal.fullscreen.isFalse || stateGlobal.isMaximized.isFalse)
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
offset: Offset(
|
||||||
|
0.0,
|
||||||
|
stateGlobal.isFocused.isTrue
|
||||||
|
? kFrameBoxShadowOffsetFocused
|
||||||
|
: kFrameBoxShadowOffsetUnfocused),
|
||||||
|
blurRadius: kFrameBoxShadowBlurRadius,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: null;
|
||||||
|
return Obx(
|
||||||
|
() => Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isMainDesktopWindow ? Colors.transparent : Theme.of(context).colorScheme.background,
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
width: stateGlobal.windowBorderWidth.value,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
(stateGlobal.fullscreen.isTrue || stateGlobal.isMaximized.isTrue)
|
||||||
|
? 0
|
||||||
|
: kFrameBorderRadius,
|
||||||
|
),
|
||||||
|
boxShadow: boxShadow(),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
(stateGlobal.fullscreen.isTrue || stateGlobal.isMaximized.isTrue)
|
||||||
|
? 0
|
||||||
|
: kFrameClipRRectBorderRadius,
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -154,9 +154,14 @@ const kDefaultScrollDuration = Duration(milliseconds: 50);
|
|||||||
const kDefaultMouseWheelThrottleDuration = Duration(milliseconds: 50);
|
const kDefaultMouseWheelThrottleDuration = Duration(milliseconds: 50);
|
||||||
const kFullScreenEdgeSize = 0.0;
|
const kFullScreenEdgeSize = 0.0;
|
||||||
const kMaximizeEdgeSize = 0.0;
|
const kMaximizeEdgeSize = 0.0;
|
||||||
var kWindowEdgeSize = isWindows ? 1.0 : 5.0;
|
final kWindowEdgeSize = isWindows ? 1.0 : 5.0;
|
||||||
const kWindowBorderWidth = 1.0;
|
final kWindowBorderWidth = isLinux ? 1.0 : 0.0;
|
||||||
const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0);
|
const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0);
|
||||||
|
const kFrameBorderRadius = 12.0;
|
||||||
|
const kFrameClipRRectBorderRadius = 12.0;
|
||||||
|
const kFrameBoxShadowBlurRadius = 32.0;
|
||||||
|
const kFrameBoxShadowOffsetFocused = 4.0;
|
||||||
|
const kFrameBoxShadowOffsetUnfocused = 2.0;
|
||||||
|
|
||||||
const kInvalidValueStr = 'InvalidValueStr';
|
const kInvalidValueStr = 'InvalidValueStr';
|
||||||
|
|
||||||
|
@ -91,18 +91,21 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final tabWidget = Container(
|
final child = Scaffold(
|
||||||
decoration: BoxDecoration(
|
backgroundColor: Theme.of(context).cardColor,
|
||||||
border: Border.all(color: MyTheme.color(context).border!)),
|
body: DesktopTab(
|
||||||
child: Scaffold(
|
controller: tabController,
|
||||||
backgroundColor: Theme.of(context).cardColor,
|
onWindowCloseButton: handleWindowCloseButton,
|
||||||
body: DesktopTab(
|
tail: const AddButton(),
|
||||||
controller: tabController,
|
labelGetter: DesktopTab.tablabelGetter,
|
||||||
onWindowCloseButton: handleWindowCloseButton,
|
));
|
||||||
tail: const AddButton(),
|
final tabWidget = isLinux
|
||||||
labelGetter: DesktopTab.tablabelGetter,
|
? buildVirtualWindowFrame(context, child)
|
||||||
)),
|
: Container(
|
||||||
);
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: MyTheme.color(context).border!)),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
return isMacOS || kUseCompatibleUiMode
|
return isMacOS || kUseCompatibleUiMode
|
||||||
? tabWidget
|
? tabWidget
|
||||||
: SubWindowDragToResizeArea(
|
: SubWindowDragToResizeArea(
|
||||||
|
@ -97,21 +97,30 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final tabWidget = Container(
|
final child = Scaffold(
|
||||||
decoration: BoxDecoration(
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
border: Border.all(color: MyTheme.color(context).border!)),
|
body: DesktopTab(
|
||||||
child: Scaffold(
|
controller: tabController,
|
||||||
backgroundColor: Theme.of(context).colorScheme.background,
|
onWindowCloseButton: () async {
|
||||||
body: DesktopTab(
|
tabController.clear();
|
||||||
controller: tabController,
|
return true;
|
||||||
onWindowCloseButton: () async {
|
},
|
||||||
tabController.clear();
|
tail: AddButton(),
|
||||||
return true;
|
labelGetter: DesktopTab.tablabelGetter,
|
||||||
},
|
),
|
||||||
tail: AddButton(),
|
|
||||||
labelGetter: DesktopTab.tablabelGetter,
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
|
final tabWidget = isLinux
|
||||||
|
? buildVirtualWindowFrame(
|
||||||
|
context,
|
||||||
|
Scaffold(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
|
body: child),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: MyTheme.color(context).border!)),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
return isMacOS || kUseCompatibleUiMode
|
return isMacOS || kUseCompatibleUiMode
|
||||||
? tabWidget
|
? tabWidget
|
||||||
: Obx(
|
: Obx(
|
||||||
|
@ -7,6 +7,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
import 'package:flutter_improved_scrolling/flutter_improved_scrolling.dart';
|
import 'package:flutter_improved_scrolling/flutter_improved_scrolling.dart';
|
||||||
|
import 'package:flutter_hbb/models/state_model.dart';
|
||||||
|
|
||||||
import '../../consts.dart';
|
import '../../consts.dart';
|
||||||
import '../../common/widgets/overlay.dart';
|
import '../../common/widgets/overlay.dart';
|
||||||
@ -165,6 +166,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
// and let OS to handle events instead.
|
// and let OS to handle events instead.
|
||||||
_rawKeyFocusNode.unfocus();
|
_rawKeyFocusNode.unfocus();
|
||||||
}
|
}
|
||||||
|
stateGlobal.isFocused.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -174,6 +176,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
if (isWindows) {
|
if (isWindows) {
|
||||||
_isWindowBlur = false;
|
_isWindowBlur = false;
|
||||||
}
|
}
|
||||||
|
stateGlobal.isFocused.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -131,103 +131,103 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final tabWidget = Obx(
|
final child = Scaffold(
|
||||||
() => Container(
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
decoration: BoxDecoration(
|
body: DesktopTab(
|
||||||
border: Border.all(
|
controller: tabController,
|
||||||
color: MyTheme.color(context).border!,
|
onWindowCloseButton: handleWindowCloseButton,
|
||||||
width: stateGlobal.windowBorderWidth.value),
|
tail: const AddButton(),
|
||||||
),
|
pageViewBuilder: (pageView) => pageView,
|
||||||
child: Scaffold(
|
labelGetter: DesktopTab.tablabelGetter,
|
||||||
backgroundColor: Theme.of(context).colorScheme.background,
|
tabBuilder: (key, icon, label, themeConf) => Obx(() {
|
||||||
body: DesktopTab(
|
final connectionType = ConnectionTypeState.find(key);
|
||||||
controller: tabController,
|
if (!connectionType.isValid()) {
|
||||||
onWindowCloseButton: handleWindowCloseButton,
|
return Row(
|
||||||
tail: const AddButton(),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
pageViewBuilder: (pageView) => pageView,
|
children: [
|
||||||
labelGetter: DesktopTab.tablabelGetter,
|
icon,
|
||||||
tabBuilder: (key, icon, label, themeConf) => Obx(() {
|
label,
|
||||||
final connectionType = ConnectionTypeState.find(key);
|
],
|
||||||
if (!connectionType.isValid()) {
|
);
|
||||||
return Row(
|
} else {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
bool secure =
|
||||||
children: [
|
connectionType.secure.value == ConnectionType.strSecure;
|
||||||
icon,
|
bool direct =
|
||||||
label,
|
connectionType.direct.value == ConnectionType.strDirect;
|
||||||
],
|
String msgConn;
|
||||||
);
|
if (secure && direct) {
|
||||||
} else {
|
msgConn = translate("Direct and encrypted connection");
|
||||||
bool secure =
|
} else if (secure && !direct) {
|
||||||
connectionType.secure.value == ConnectionType.strSecure;
|
msgConn = translate("Relayed and encrypted connection");
|
||||||
bool direct =
|
} else if (!secure && direct) {
|
||||||
connectionType.direct.value == ConnectionType.strDirect;
|
msgConn = translate("Direct and unencrypted connection");
|
||||||
String msgConn;
|
} else {
|
||||||
if (secure && direct) {
|
msgConn = translate("Relayed and unencrypted connection");
|
||||||
msgConn = translate("Direct and encrypted connection");
|
}
|
||||||
} else if (secure && !direct) {
|
var msgFingerprint = '${translate('Fingerprint')}:\n';
|
||||||
msgConn = translate("Relayed and encrypted connection");
|
var fingerprint = FingerprintState.find(key).value;
|
||||||
} else if (!secure && direct) {
|
if (fingerprint.isEmpty) {
|
||||||
msgConn = translate("Direct and unencrypted connection");
|
fingerprint = 'N/A';
|
||||||
} else {
|
}
|
||||||
msgConn = translate("Relayed and unencrypted connection");
|
if (fingerprint.length > 5 * 8) {
|
||||||
}
|
var first = fingerprint.substring(0, 39);
|
||||||
var msgFingerprint = '${translate('Fingerprint')}:\n';
|
var second = fingerprint.substring(40);
|
||||||
var fingerprint = FingerprintState.find(key).value;
|
msgFingerprint += '$first\n$second';
|
||||||
if (fingerprint.isEmpty) {
|
} else {
|
||||||
fingerprint = 'N/A';
|
msgFingerprint += fingerprint;
|
||||||
}
|
}
|
||||||
if (fingerprint.length > 5 * 8) {
|
|
||||||
var first = fingerprint.substring(0, 39);
|
|
||||||
var second = fingerprint.substring(40);
|
|
||||||
msgFingerprint += '$first\n$second';
|
|
||||||
} else {
|
|
||||||
msgFingerprint += fingerprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
final tab = Row(
|
final tab = Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
icon,
|
icon,
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: '$msgConn\n$msgFingerprint',
|
message: '$msgConn\n$msgFingerprint',
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
'assets/${connectionType.secure.value}${connectionType.direct.value}.svg',
|
'assets/${connectionType.secure.value}${connectionType.direct.value}.svg',
|
||||||
width: themeConf.iconSize,
|
width: themeConf.iconSize,
|
||||||
height: themeConf.iconSize,
|
height: themeConf.iconSize,
|
||||||
).paddingOnly(right: 5),
|
).paddingOnly(right: 5),
|
||||||
),
|
),
|
||||||
label,
|
label,
|
||||||
unreadMessageCountBuilder(UnreadChatCountState.find(key))
|
unreadMessageCountBuilder(UnreadChatCountState.find(key))
|
||||||
.marginOnly(left: 4),
|
.marginOnly(left: 4),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return Listener(
|
return Listener(
|
||||||
onPointerDown: (e) {
|
onPointerDown: (e) {
|
||||||
if (e.kind != ui.PointerDeviceKind.mouse) {
|
if (e.kind != ui.PointerDeviceKind.mouse) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final remotePage = tabController.state.value.tabs
|
final remotePage = tabController.state.value.tabs
|
||||||
.firstWhere((tab) => tab.key == key)
|
.firstWhere((tab) => tab.key == key)
|
||||||
.page as RemotePage;
|
.page as RemotePage;
|
||||||
if (remotePage.ffi.ffiModel.pi.isSet.isTrue &&
|
if (remotePage.ffi.ffiModel.pi.isSet.isTrue && e.buttons == 2) {
|
||||||
e.buttons == 2) {
|
showRightMenu(
|
||||||
showRightMenu(
|
(CancelFunc cancelFunc) {
|
||||||
(CancelFunc cancelFunc) {
|
return _tabMenuBuilder(key, cancelFunc);
|
||||||
return _tabMenuBuilder(key, cancelFunc);
|
},
|
||||||
},
|
target: e.position,
|
||||||
target: e.position,
|
);
|
||||||
);
|
}
|
||||||
}
|
},
|
||||||
},
|
child: tab,
|
||||||
child: tab,
|
);
|
||||||
);
|
}
|
||||||
}
|
}),
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
final tabWidget = isLinux
|
||||||
|
? buildVirtualWindowFrame(context, child)
|
||||||
|
: Obx(() => Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: MyTheme.color(context).border!,
|
||||||
|
width: stateGlobal.windowBorderWidth.value),
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
));
|
||||||
return isMacOS || kUseCompatibleUiMode
|
return isMacOS || kUseCompatibleUiMode
|
||||||
? tabWidget
|
? tabWidget
|
||||||
: Obx(() => SubWindowDragToResizeArea(
|
: Obx(() => SubWindowDragToResizeArea(
|
||||||
|
@ -77,14 +77,20 @@ class _DesktopServerPageState extends State<DesktopServerPage>
|
|||||||
ChangeNotifierProvider.value(value: gFFI.chatModel),
|
ChangeNotifierProvider.value(value: gFFI.chatModel),
|
||||||
],
|
],
|
||||||
child: Consumer<ServerModel>(
|
child: Consumer<ServerModel>(
|
||||||
builder: (context, serverModel, child) => Container(
|
builder: (context, serverModel, child) {
|
||||||
decoration: BoxDecoration(
|
final body = Scaffold(
|
||||||
border: Border.all(color: MyTheme.color(context).border!)),
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
body: ConnectionManager(),
|
body: ConnectionManager(),
|
||||||
),
|
);
|
||||||
),
|
return isLinux
|
||||||
|
? buildVirtualWindowFrame(context, body)
|
||||||
|
: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border:
|
||||||
|
Border.all(color: MyTheme.color(context).border!)),
|
||||||
|
child: body,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ class DesktopFileTransferScreen extends StatelessWidget {
|
|||||||
ChangeNotifierProvider.value(value: gFFI.canvasModel),
|
ChangeNotifierProvider.value(value: gFFI.canvasModel),
|
||||||
],
|
],
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
backgroundColor: isLinux ? Colors.transparent : null,
|
||||||
body: FileManagerTabPage(
|
body: FileManagerTabPage(
|
||||||
params: params,
|
params: params,
|
||||||
),
|
),
|
||||||
|
@ -17,6 +17,7 @@ class DesktopPortForwardScreen extends StatelessWidget {
|
|||||||
ChangeNotifierProvider.value(value: gFFI.ffiModel),
|
ChangeNotifierProvider.value(value: gFFI.ffiModel),
|
||||||
],
|
],
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
backgroundColor: isLinux ? Colors.transparent : null,
|
||||||
body: PortForwardTabPage(
|
body: PortForwardTabPage(
|
||||||
params: params,
|
params: params,
|
||||||
),
|
),
|
||||||
|
@ -548,6 +548,16 @@ class WindowActionPanelState extends State<WindowActionPanel>
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onWindowFocus() {
|
||||||
|
stateGlobal.isFocused.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onWindowBlur() {
|
||||||
|
stateGlobal.isFocused.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onWindowMinimize() {
|
void onWindowMinimize() {
|
||||||
stateGlobal.setMinimized(true);
|
stateGlobal.setMinimized(true);
|
||||||
|
@ -440,6 +440,9 @@ class _AppState extends State<App> {
|
|||||||
if (isDesktop && desktopType == DesktopType.main) {
|
if (isDesktop && desktopType == DesktopType.main) {
|
||||||
child = keyListenerBuilder(context, child);
|
child = keyListenerBuilder(context, child);
|
||||||
}
|
}
|
||||||
|
if (isLinux) {
|
||||||
|
child = buildVirtualWindowFrame(context, child);
|
||||||
|
}
|
||||||
return child;
|
return child;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -20,6 +20,7 @@ class StateGlobal {
|
|||||||
final svcStatus = SvcStatus.notReady.obs;
|
final svcStatus = SvcStatus.notReady.obs;
|
||||||
// Only used for macOS
|
// Only used for macOS
|
||||||
bool? closeOnFullscreen;
|
bool? closeOnFullscreen;
|
||||||
|
final RxBool isFocused = false.obs;
|
||||||
|
|
||||||
String _inputSource = '';
|
String _inputSource = '';
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ static void my_application_activate(GApplication* application) {
|
|||||||
MyApplication* self = MY_APPLICATION(application);
|
MyApplication* self = MY_APPLICATION(application);
|
||||||
GtkWindow* window =
|
GtkWindow* window =
|
||||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||||
// we have custom window frame
|
|
||||||
gtk_window_set_decorated(window, FALSE);
|
gtk_window_set_decorated(window, FALSE);
|
||||||
// try setting icon for rustdesk, which uses the system cache
|
// try setting icon for rustdesk, which uses the system cache
|
||||||
GtkIconTheme* theme = gtk_icon_theme_get_default();
|
GtkIconTheme* theme = gtk_icon_theme_get_default();
|
||||||
@ -75,12 +74,7 @@ static void my_application_activate(GApplication* application) {
|
|||||||
|
|
||||||
FlView* view = fl_view_new(project);
|
FlView* view = fl_view_new(project);
|
||||||
gtk_widget_show(GTK_WIDGET(view));
|
gtk_widget_show(GTK_WIDGET(view));
|
||||||
|
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
|
||||||
auto border_frame = gtk_frame_new(nullptr);
|
|
||||||
gtk_frame_set_shadow_type(GTK_FRAME(border_frame), GTK_SHADOW_ETCHED_IN);
|
|
||||||
gtk_container_add(GTK_CONTAINER(border_frame), GTK_WIDGET(view));
|
|
||||||
gtk_widget_show(GTK_WIDGET(border_frame));
|
|
||||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(border_frame));
|
|
||||||
|
|
||||||
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user