mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-06-22 10:02:20 +00:00
Merge fad445ca16 into 2b40c61d8e
This commit is contained in:
commit
702f03e9db
3 changed files with 141 additions and 62 deletions
|
|
@ -9,6 +9,7 @@ import 'package:flutter_hbb/common/hbbs/hbbs.dart';
|
|||
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||
import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:flutter_hbb/common/widgets/resizable_side_panel.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
||||
import 'package:flutter_hbb/models/ab_model.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
|
|
@ -36,6 +37,8 @@ class AddressBook extends StatefulWidget {
|
|||
|
||||
class _AddressBookState extends State<AddressBook> {
|
||||
var menuPos = RelativeRect.fill;
|
||||
final _tagsPanel = ResizablePanelController(
|
||||
optionKey: kOptionAbTagsPanelWidth, defaultWidth: 200, maxWidth: 300);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Obx(() {
|
||||
|
|
@ -73,39 +76,43 @@ class _AddressBookState extends State<AddressBook> {
|
|||
});
|
||||
|
||||
Widget _buildAddressBookLandscape() {
|
||||
return Row(
|
||||
children: [
|
||||
Offstage(
|
||||
offstage: hideAbTagsPanel.value,
|
||||
final panel = Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border:
|
||||
Border.all(color: Theme.of(context).colorScheme.background)),
|
||||
height: double.infinity,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildAbDropdown(),
|
||||
_buildTagHeader().marginOnly(
|
||||
left: 8.0,
|
||||
right: gFFI.abModel.legacyMode.value ? 8.0 : 0,
|
||||
top: gFFI.abModel.legacyMode.value ? 8.0 : 0),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.background)),
|
||||
child: Container(
|
||||
width: 200,
|
||||
height: double.infinity,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildAbDropdown(),
|
||||
_buildTagHeader().marginOnly(
|
||||
left: 8.0,
|
||||
right: gFFI.abModel.legacyMode.value ? 8.0 : 0,
|
||||
top: gFFI.abModel.legacyMode.value ? 8.0 : 0),
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: _buildTags(),
|
||||
),
|
||||
),
|
||||
_buildAbPermission(),
|
||||
],
|
||||
),
|
||||
),
|
||||
).marginOnly(right: 12.0)),
|
||||
_buildPeersViews()
|
||||
],
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: _buildTags(),
|
||||
),
|
||||
),
|
||||
_buildAbPermission(),
|
||||
],
|
||||
),
|
||||
);
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) => Row(
|
||||
children: [
|
||||
Offstage(
|
||||
offstage: hideAbTagsPanel.value,
|
||||
child: Obx(() => SizedBox(
|
||||
width: _tagsPanel.effectiveWidth(constraints.maxWidth),
|
||||
child: panel,
|
||||
))),
|
||||
if (!hideAbTagsPanel.value) _tagsPanel.buildDivider(context),
|
||||
_buildPeersViews()
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:flutter_hbb/common/hbbs/hbbs.dart';
|
|||
import 'package:flutter_hbb/common/widgets/login.dart';
|
||||
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:flutter_hbb/common/widgets/resizable_side_panel.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
|
|
@ -26,6 +27,10 @@ class _MyGroupState extends State<MyGroup> {
|
|||
RxString get searchAccessibleItemNameText =>
|
||||
gFFI.groupModel.searchAccessibleItemNameText;
|
||||
static TextEditingController searchUserController = TextEditingController();
|
||||
final _devicesPanel = ResizablePanelController(
|
||||
optionKey: kOptionAccessibleDevicesPanelWidth,
|
||||
defaultWidth: 150,
|
||||
maxWidth: 300);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -58,38 +63,42 @@ class _MyGroupState extends State<MyGroup> {
|
|||
}
|
||||
|
||||
Widget _buildLandscape() {
|
||||
return Row(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border:
|
||||
Border.all(color: Theme.of(context).colorScheme.background)),
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: double.infinity,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildLeftHeader(),
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: _buildLeftList(),
|
||||
),
|
||||
)
|
||||
],
|
||||
final panel = Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border:
|
||||
Border.all(color: Theme.of(context).colorScheme.background)),
|
||||
height: double.infinity,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildLeftHeader(),
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
child: _buildLeftList(),
|
||||
),
|
||||
),
|
||||
).marginOnly(right: 12.0),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: MyGroupPeerView(
|
||||
menuPadding: widget.menuPadding,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) => Row(
|
||||
children: [
|
||||
Obx(() => SizedBox(
|
||||
width: _devicesPanel.effectiveWidth(constraints.maxWidth),
|
||||
child: panel,
|
||||
)),
|
||||
)
|
||||
],
|
||||
_devicesPanel.buildDivider(context),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: MyGroupPeerView(
|
||||
menuPadding: widget.menuPadding,
|
||||
)),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
63
flutter/lib/common/widgets/resizable_side_panel.dart
Normal file
63
flutter/lib/common/widgets/resizable_side_panel.dart
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'dart:math';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
// Persisted-width option keys for the resizable left panels.
|
||||
const String kOptionAbTagsPanelWidth = 'ab-tags-panel-width';
|
||||
const String kOptionAccessibleDevicesPanelWidth = 'accessible-devices-panel-width';
|
||||
|
||||
class ResizablePanelController {
|
||||
final String optionKey;
|
||||
final double defaultWidth;
|
||||
final double minWidth;
|
||||
final double maxWidth;
|
||||
late final RxDouble width;
|
||||
|
||||
static const double dividerHitWidth = 12.0;
|
||||
static const double minContentWidth = 120.0;
|
||||
|
||||
ResizablePanelController({
|
||||
required this.optionKey,
|
||||
required this.defaultWidth,
|
||||
this.minWidth = 120,
|
||||
this.maxWidth = 300,
|
||||
}) {
|
||||
final saved = double.tryParse(bind.mainGetLocalOption(key: optionKey));
|
||||
width =
|
||||
RxDouble((saved ?? defaultWidth).clamp(minWidth, maxWidth).toDouble());
|
||||
}
|
||||
|
||||
void _onDrag(double dx) {
|
||||
width.value = (width.value + dx).clamp(minWidth, maxWidth).toDouble();
|
||||
}
|
||||
|
||||
double effectiveWidth(double available) {
|
||||
if (!available.isFinite) return width.value;
|
||||
final maxAllowed = available - dividerHitWidth - minContentWidth;
|
||||
return width.value.clamp(minWidth, max(minWidth, maxAllowed)).toDouble();
|
||||
}
|
||||
|
||||
void _persist() {
|
||||
bind.mainSetLocalOption(
|
||||
key: optionKey, value: width.value.toStringAsFixed(0));
|
||||
}
|
||||
|
||||
Widget buildDivider(BuildContext context) {
|
||||
final sign = Directionality.of(context) == TextDirection.rtl ? -1.0 : 1.0;
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.resizeLeftRight,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onHorizontalDragUpdate: (details) => _onDrag(sign * details.delta.dx),
|
||||
onHorizontalDragEnd: (_) => _persist(),
|
||||
onHorizontalDragCancel: _persist,
|
||||
child: Container(
|
||||
width: dividerHitWidth,
|
||||
height: double.infinity,
|
||||
color: Colors.transparent,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue