mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-03-29 08:01:03 +03:00
Fix Terminal top content overlapping with notch (SafeArea) (#13724)
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:math';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
@@ -29,9 +31,12 @@ class TerminalPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TerminalPageState extends State<TerminalPage>
|
class _TerminalPageState extends State<TerminalPage>
|
||||||
with AutomaticKeepAliveClientMixin {
|
with AutomaticKeepAliveClientMixin, WidgetsBindingObserver {
|
||||||
late FFI _ffi;
|
late FFI _ffi;
|
||||||
late TerminalModel _terminalModel;
|
late TerminalModel _terminalModel;
|
||||||
|
double? _cellHeight;
|
||||||
|
double _sysKeyboardHeight = 0;
|
||||||
|
Timer? _keyboardDebounce;
|
||||||
|
|
||||||
// For web only.
|
// For web only.
|
||||||
// 'monospace' does not work on web, use Google Fonts, `??` is only for null safety.
|
// 'monospace' does not work on web, use Google Fonts, `??` is only for null safety.
|
||||||
@@ -44,6 +49,7 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
debugPrint(
|
debugPrint(
|
||||||
'[TerminalPage] Initializing terminal ${widget.terminalId} for peer ${widget.id}');
|
'[TerminalPage] Initializing terminal ${widget.terminalId} for peer ${widget.id}');
|
||||||
@@ -62,6 +68,10 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
debugPrint(
|
debugPrint(
|
||||||
'[TerminalPage] Terminal model created for terminal ${widget.terminalId}');
|
'[TerminalPage] Terminal model created for terminal ${widget.terminalId}');
|
||||||
|
|
||||||
|
_terminalModel.onResizeExternal = (w, h, pw, ph) {
|
||||||
|
_cellHeight = ph * 1.0;
|
||||||
|
};
|
||||||
|
|
||||||
// Register this terminal model with FFI for event routing
|
// Register this terminal model with FFI for event routing
|
||||||
_ffi.registerTerminalModel(widget.terminalId, _terminalModel);
|
_ffi.registerTerminalModel(widget.terminalId, _terminalModel);
|
||||||
|
|
||||||
@@ -78,10 +88,36 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
// Unregister terminal model from FFI
|
// Unregister terminal model from FFI
|
||||||
_ffi.unregisterTerminalModel(widget.terminalId);
|
_ffi.unregisterTerminalModel(widget.terminalId);
|
||||||
_terminalModel.dispose();
|
_terminalModel.dispose();
|
||||||
|
_keyboardDebounce?.cancel();
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
TerminalConnectionManager.releaseConnection(widget.id);
|
TerminalConnectionManager.releaseConnection(widget.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeMetrics() {
|
||||||
|
super.didChangeMetrics();
|
||||||
|
|
||||||
|
_keyboardDebounce?.cancel();
|
||||||
|
_keyboardDebounce = Timer(const Duration(milliseconds: 20), () {
|
||||||
|
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
|
||||||
|
setState(() {
|
||||||
|
_sysKeyboardHeight = bottomInset;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeInsets _calculatePadding(double heightPx) {
|
||||||
|
if (_cellHeight == null) {
|
||||||
|
return const EdgeInsets.symmetric(horizontal: 5.0, vertical: 2.0);
|
||||||
|
}
|
||||||
|
final realHeight = heightPx - _sysKeyboardHeight;
|
||||||
|
final rows = (realHeight / _cellHeight!).floor();
|
||||||
|
final extraSpace = realHeight - rows * _cellHeight!;
|
||||||
|
final topBottom = max(0.0, extraSpace / 2.0);
|
||||||
|
return EdgeInsets.only(left: 5.0, right: 5.0, top: topBottom, bottom: topBottom + _sysKeyboardHeight);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
@@ -96,28 +132,37 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
|
|
||||||
Widget buildBody() {
|
Widget buildBody() {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false, // Disable automatic layout adjustment; manually control UI updates to prevent flickering when the keyboard shows/hides
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
body: TerminalView(
|
body: SafeArea(
|
||||||
_terminalModel.terminal,
|
top: true,
|
||||||
controller: _terminalModel.terminalController,
|
child: LayoutBuilder(
|
||||||
autofocus: true,
|
builder: (context, constraints) {
|
||||||
textStyle: _getTerminalStyle(),
|
final heightPx = constraints.maxHeight;
|
||||||
backgroundOpacity: 0.7,
|
return TerminalView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 2.0),
|
_terminalModel.terminal,
|
||||||
onSecondaryTapDown: (details, offset) async {
|
controller: _terminalModel.terminalController,
|
||||||
final selection = _terminalModel.terminalController.selection;
|
autofocus: true,
|
||||||
if (selection != null) {
|
textStyle: _getTerminalStyle(),
|
||||||
final text = _terminalModel.terminal.buffer.getText(selection);
|
backgroundOpacity: 0.7,
|
||||||
_terminalModel.terminalController.clearSelection();
|
padding: _calculatePadding(heightPx),
|
||||||
await Clipboard.setData(ClipboardData(text: text));
|
onSecondaryTapDown: (details, offset) async {
|
||||||
} else {
|
final selection = _terminalModel.terminalController.selection;
|
||||||
final data = await Clipboard.getData('text/plain');
|
if (selection != null) {
|
||||||
final text = data?.text;
|
final text = _terminalModel.terminal.buffer.getText(selection);
|
||||||
if (text != null) {
|
_terminalModel.terminalController.clearSelection();
|
||||||
_terminalModel.terminal.paste(text);
|
await Clipboard.setData(ClipboardData(text: text));
|
||||||
}
|
} else {
|
||||||
}
|
final data = await Clipboard.getData('text/plain');
|
||||||
},
|
final text = data?.text;
|
||||||
|
if (text != null) {
|
||||||
|
_terminalModel.terminal.paste(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user