refact: remote toolbar show/hide (#13843)
Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -120,6 +120,7 @@ const String kOptionApproveMode = "approve-mode";
|
|||||||
const String kOptionAllowNumericOneTimePassword =
|
const String kOptionAllowNumericOneTimePassword =
|
||||||
"allow-numeric-one-time-password";
|
"allow-numeric-one-time-password";
|
||||||
const String kOptionCollapseToolbar = "collapse_toolbar";
|
const String kOptionCollapseToolbar = "collapse_toolbar";
|
||||||
|
const String kOptionHideToolbar = "hide-toolbar";
|
||||||
const String kOptionShowRemoteCursor = "show_remote_cursor";
|
const String kOptionShowRemoteCursor = "show_remote_cursor";
|
||||||
const String kOptionFollowRemoteCursor = "follow_remote_cursor";
|
const String kOptionFollowRemoteCursor = "follow_remote_cursor";
|
||||||
const String kOptionFollowRemoteWindow = "follow_remote_window";
|
const String kOptionFollowRemoteWindow = "follow_remote_window";
|
||||||
|
|||||||
@@ -509,7 +509,6 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
() => _ffi.ffiModel.pi.isSet.isFalse
|
() => _ffi.ffiModel.pi.isSet.isFalse
|
||||||
? Container(color: Colors.transparent)
|
? Container(color: Colors.transparent)
|
||||||
: Obx(() {
|
: Obx(() {
|
||||||
widget.toolbarState.initShow(sessionId);
|
|
||||||
_ffi.textureModel.updateCurrentDisplay(peerDisplay.value);
|
_ffi.textureModel.updateCurrentDisplay(peerDisplay.value);
|
||||||
return ImagePaint(
|
return ImagePaint(
|
||||||
id: widget.id,
|
id: widget.id,
|
||||||
|
|||||||
@@ -251,11 +251,11 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
MenuEntryButton<String>(
|
MenuEntryButton<String>(
|
||||||
childBuilder: (TextStyle? style) => Obx(() => Text(
|
childBuilder: (TextStyle? style) => Obx(() => Text(
|
||||||
translate(
|
translate(
|
||||||
toolbarState.show.isTrue ? 'Hide Toolbar' : 'Show Toolbar'),
|
toolbarState.hide.isTrue ? 'Show Toolbar' : 'Hide Toolbar'),
|
||||||
style: style,
|
style: style,
|
||||||
)),
|
)),
|
||||||
proc: () {
|
proc: () {
|
||||||
toolbarState.switchShow(sessionId);
|
toolbarState.switchHide(sessionId);
|
||||||
cancelFunc();
|
cancelFunc();
|
||||||
},
|
},
|
||||||
padding: padding,
|
padding: padding,
|
||||||
|
|||||||
@@ -465,7 +465,6 @@ class _ViewCameraPageState extends State<ViewCameraPage>
|
|||||||
() => _ffi.ffiModel.pi.isSet.isFalse
|
() => _ffi.ffiModel.pi.isSet.isFalse
|
||||||
? Container(color: Colors.transparent)
|
? Container(color: Colors.transparent)
|
||||||
: Obx(() {
|
: Obx(() {
|
||||||
widget.toolbarState.initShow(sessionId);
|
|
||||||
_ffi.textureModel.updateCurrentDisplay(peerDisplay.value);
|
_ffi.textureModel.updateCurrentDisplay(peerDisplay.value);
|
||||||
return ImagePaint(
|
return ImagePaint(
|
||||||
id: widget.id,
|
id: widget.id,
|
||||||
|
|||||||
@@ -250,11 +250,11 @@ class _ViewCameraTabPageState extends State<ViewCameraTabPage> {
|
|||||||
MenuEntryButton<String>(
|
MenuEntryButton<String>(
|
||||||
childBuilder: (TextStyle? style) => Obx(() => Text(
|
childBuilder: (TextStyle? style) => Obx(() => Text(
|
||||||
translate(
|
translate(
|
||||||
toolbarState.show.isTrue ? 'Hide Toolbar' : 'Show Toolbar'),
|
toolbarState.hide.isTrue ? 'Show Toolbar' : 'Hide Toolbar'),
|
||||||
style: style,
|
style: style,
|
||||||
)),
|
)),
|
||||||
proc: () {
|
proc: () {
|
||||||
toolbarState.switchShow(sessionId);
|
toolbarState.switchHide(sessionId);
|
||||||
cancelFunc();
|
cancelFunc();
|
||||||
},
|
},
|
||||||
padding: padding,
|
padding: padding,
|
||||||
|
|||||||
@@ -31,8 +31,12 @@ import 'package:flutter_hbb/common/widgets/custom_scale_base.dart';
|
|||||||
class ToolbarState {
|
class ToolbarState {
|
||||||
late RxBool _pin;
|
late RxBool _pin;
|
||||||
|
|
||||||
bool isShowInited = false;
|
RxBool collapse = false.obs;
|
||||||
RxBool show = false.obs;
|
RxBool hide = false.obs;
|
||||||
|
|
||||||
|
// Track initialization state to prevent flickering
|
||||||
|
final RxBool initialized = false.obs;
|
||||||
|
bool _isInitializing = false;
|
||||||
|
|
||||||
ToolbarState() {
|
ToolbarState() {
|
||||||
_pin = RxBool(false);
|
_pin = RxBool(false);
|
||||||
@@ -53,19 +57,39 @@ class ToolbarState {
|
|||||||
|
|
||||||
bool get pin => _pin.value;
|
bool get pin => _pin.value;
|
||||||
|
|
||||||
switchShow(SessionID sessionId) async {
|
/// Initialize all toolbar states from session options.
|
||||||
bind.sessionToggleOption(
|
/// This should be called once when the toolbar is first created.
|
||||||
sessionId: sessionId, value: kOptionCollapseToolbar);
|
Future<void> init(SessionID sessionId) async {
|
||||||
show.value = !show.value;
|
if (initialized.value || _isInitializing) return;
|
||||||
|
_isInitializing = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Load both states in parallel for better performance
|
||||||
|
final results = await Future.wait([
|
||||||
|
bind.sessionGetToggleOption(
|
||||||
|
sessionId: sessionId, arg: kOptionCollapseToolbar),
|
||||||
|
bind.sessionGetToggleOption(
|
||||||
|
sessionId: sessionId, arg: kOptionHideToolbar),
|
||||||
|
]);
|
||||||
|
|
||||||
|
collapse.value = results[0] ?? false;
|
||||||
|
hide.value = results[1] ?? false;
|
||||||
|
} finally {
|
||||||
|
_isInitializing = false;
|
||||||
|
initialized.value = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initShow(SessionID sessionId) async {
|
switchCollapse(SessionID sessionId) async {
|
||||||
if (!isShowInited) {
|
bind.sessionToggleOption(
|
||||||
show.value = !(await bind.sessionGetToggleOption(
|
sessionId: sessionId, value: kOptionCollapseToolbar);
|
||||||
sessionId: sessionId, arg: kOptionCollapseToolbar) ??
|
collapse.value = !collapse.value;
|
||||||
false);
|
}
|
||||||
isShowInited = true;
|
|
||||||
}
|
// Switch hide state for entire toolbar visibility
|
||||||
|
switchHide(SessionID sessionId) async {
|
||||||
|
bind.sessionToggleOption(sessionId: sessionId, value: kOptionHideToolbar);
|
||||||
|
hide.value = !hide.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
switchPin() async {
|
switchPin() async {
|
||||||
@@ -237,7 +261,8 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
|
|||||||
// setState(() {});
|
// setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
RxBool get show => widget.state.show;
|
RxBool get collapse => widget.state.collapse;
|
||||||
|
RxBool get hide => widget.state.hide;
|
||||||
bool get pin => widget.state.pin;
|
bool get pin => widget.state.pin;
|
||||||
|
|
||||||
PeerInfo get pi => widget.ffi.ffiModel.pi;
|
PeerInfo get pi => widget.ffi.ffiModel.pi;
|
||||||
@@ -258,6 +283,8 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
|
|||||||
arg: 'remote-menubar-drag-x') ??
|
arg: 'remote-menubar-drag-x') ??
|
||||||
'0.5') ??
|
'0.5') ??
|
||||||
0.5;
|
0.5;
|
||||||
|
// Initialize toolbar states (collapse, hide) from session options
|
||||||
|
widget.state.init(widget.ffi.sessionId);
|
||||||
});
|
});
|
||||||
|
|
||||||
_debouncerHide = Debouncer<int>(
|
_debouncerHide = Debouncer<int>(
|
||||||
@@ -277,8 +304,8 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_debouncerHideProc(int v) {
|
_debouncerHideProc(int v) {
|
||||||
if (!pin && show.isTrue && _isCursorOverImage && _dragging.isFalse) {
|
if (!pin && collapse.isFalse && _isCursorOverImage && _dragging.isFalse) {
|
||||||
show.value = false;
|
collapse.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,17 +318,27 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Align(
|
return Obx(() {
|
||||||
alignment: Alignment.topCenter,
|
// Wait for initialization to complete to prevent flickering
|
||||||
child: Obx(() => show.value
|
if (!widget.state.initialized.value) {
|
||||||
? _buildToolbar(context)
|
return const SizedBox.shrink();
|
||||||
: _buildDraggableShowHide(context)),
|
}
|
||||||
);
|
// If toolbar is hidden, return empty widget
|
||||||
|
if (hide.value) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: collapse.isFalse
|
||||||
|
? _buildToolbar(context)
|
||||||
|
: _buildDraggableCollapse(context),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDraggableShowHide(BuildContext context) {
|
Widget _buildDraggableCollapse(BuildContext context) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
if (show.isTrue && _dragging.isFalse) {
|
if (collapse.isFalse && _dragging.isFalse) {
|
||||||
triggerAutoHide();
|
triggerAutoHide();
|
||||||
}
|
}
|
||||||
final borderRadius = BorderRadius.vertical(
|
final borderRadius = BorderRadius.vertical(
|
||||||
@@ -398,7 +435,7 @@ class _RemoteToolbarState extends State<RemoteToolbar> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_buildDraggableShowHide(context),
|
_buildDraggableCollapse(context),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2491,7 +2528,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
|
|||||||
double left = 0.0;
|
double left = 0.0;
|
||||||
double right = 1.0;
|
double right = 1.0;
|
||||||
|
|
||||||
RxBool get show => widget.toolbarState.show;
|
RxBool get collapse => widget.toolbarState.collapse;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
initState() {
|
initState() {
|
||||||
@@ -2614,20 +2651,20 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
|
|||||||
)),
|
)),
|
||||||
buttonWrapper(
|
buttonWrapper(
|
||||||
() => setState(() {
|
() => setState(() {
|
||||||
widget.toolbarState.switchShow(widget.sessionId);
|
widget.toolbarState.switchCollapse(widget.sessionId);
|
||||||
}),
|
}),
|
||||||
Obx((() => Tooltip(
|
Obx((() => Tooltip(
|
||||||
message:
|
message: translate(
|
||||||
translate(show.isTrue ? 'Hide Toolbar' : 'Show Toolbar'),
|
collapse.isFalse ? 'Hide Toolbar' : 'Show Toolbar'),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
show.isTrue ? Icons.expand_less : Icons.expand_more,
|
collapse.isFalse ? Icons.expand_less : Icons.expand_more,
|
||||||
size: iconSize,
|
size: iconSize,
|
||||||
),
|
),
|
||||||
))),
|
))),
|
||||||
),
|
),
|
||||||
if (isWebDesktop)
|
if (isWebDesktop)
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (show.isTrue) {
|
if (collapse.isFalse) {
|
||||||
return Offstage();
|
return Offstage();
|
||||||
} else {
|
} else {
|
||||||
return buttonWrapper(
|
return buttonWrapper(
|
||||||
|
|||||||
Reference in New Issue
Block a user