fix(studio): keep sidebar expanded while channel menu is open

Opening the channel switcher let the hover-exit collapse the rail at the
same moment, leaving the menu floating at the pill's old (expanded)
position. The pill now signals open/close; the sidebar suppresses its
collapse (_menuOpen) while the menu is up, so it stays aligned.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-06-22 01:04:17 +02:00
parent 27cf7e8382
commit 46918769ce

View file

@ -701,6 +701,10 @@ class _SidebarState extends State<_Sidebar>
static const double _channelRowH = 28; static const double _channelRowH = 28;
static const double _rowGap = 8; static const double _rowGap = 8;
late final AnimationController _ctrl; late final AnimationController _ctrl;
// True while the channel-switch menu is open suppresses the
// hover-exit collapse so the rail stays expanded and the menu stays
// aligned to the pill (otherwise it floats at the pill's old x).
bool _menuOpen = false;
@override @override
void initState() { void initState() {
@ -760,7 +764,9 @@ class _SidebarState extends State<_Sidebar>
widget.activeChannel != null && widget.activeChannel!.isNotEmpty; widget.activeChannel != null && widget.activeChannel!.isNotEmpty;
return MouseRegion( return MouseRegion(
onEnter: widget.forceExpanded ? null : (_) => _ctrl.forward(), onEnter: widget.forceExpanded ? null : (_) => _ctrl.forward(),
onExit: widget.forceExpanded ? null : (_) => _ctrl.reverse(), onExit: (widget.forceExpanded || _menuOpen)
? null
: (_) => _ctrl.reverse(),
child: AnimatedBuilder( child: AnimatedBuilder(
animation: _ctrl, animation: _ctrl,
builder: (context, _) { builder: (context, _) {
@ -843,7 +849,18 @@ class _SidebarState extends State<_Sidebar>
channel: widget.activeChannel!, channel: widget.activeChannel!,
), ),
), ),
label: _ChannelPill(channel: widget.activeChannel!), label: _ChannelPill(
channel: widget.activeChannel!,
onMenuOpen: () {
setState(() => _menuOpen = true);
_ctrl.forward();
},
onMenuClose: () {
if (!mounted) return;
setState(() => _menuOpen = false);
_ctrl.reverse();
},
),
t: t, t: t,
labelsInteractive: labelsInteractive, labelsInteractive: labelsInteractive,
) )
@ -1140,7 +1157,17 @@ class _ChannelMenuItem extends StatelessWidget {
/// unmistakeable. /// unmistakeable.
class _ChannelPill extends StatelessWidget { class _ChannelPill extends StatelessWidget {
final String channel; final String channel;
const _ChannelPill({required this.channel});
/// Fired when the switch menu opens / closes so the parent sidebar can
/// stay expanded while it's up — otherwise the hover-exit collapses the
/// rail and the menu floats at the pill's old (expanded) position.
final VoidCallback? onMenuOpen;
final VoidCallback? onMenuClose;
const _ChannelPill({
required this.channel,
this.onMenuOpen,
this.onMenuClose,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -1154,7 +1181,11 @@ class _ChannelPill extends StatelessWidget {
borderRadius: BorderRadius.circular(ChainRadius.sm), borderRadius: BorderRadius.circular(ChainRadius.sm),
child: InkWell( child: InkWell(
borderRadius: BorderRadius.circular(ChainRadius.sm), borderRadius: BorderRadius.circular(ChainRadius.sm),
onTap: () => _showChannelSwitchMenu(context, channel), onTap: () async {
onMenuOpen?.call();
await _showChannelSwitchMenu(context, channel);
onMenuClose?.call();
},
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: ChainSpace.sm, horizontal: ChainSpace.sm,