This commit is contained in:
StealUrKill 2026-06-22 15:28:53 +08:00 committed by GitHub
commit 702f03e9db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 141 additions and 62 deletions

View file

@ -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()
],
),
);
}

View file

@ -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,
)),
)
],
),
);
}

View 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,
),
),
);
}
}