Files
sm-emby-share/lib/features/player/widgets/player_controls_chrome.dart
T

162 lines
4.8 KiB
Dart
Raw Normal View History

2026-07-14 11:11:36 +08:00
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
import '../../../shared/theme/app_theme.dart';
import '../../../shared/widgets/top_drag_area.dart';
class ControlsChrome extends StatelessWidget {
final bool visible;
final List<Widget> topBar;
final double topBarLeftInset;
final double topBarTopInset;
final Widget bottomBar;
final Widget? centerBar;
final VoidCallback? onControlsAreaTap;
final ValueChanged<bool>? onControlsHoverChanged;
final Widget? leftBar;
final Widget? rightBar;
final bool isWindowed;
final bool isPip;
const ControlsChrome({
super.key,
required this.visible,
required this.topBar,
this.topBarLeftInset = 8,
this.topBarTopInset = 8,
required this.bottomBar,
this.centerBar,
this.leftBar,
this.rightBar,
required this.onControlsAreaTap,
this.onControlsHoverChanged,
this.isWindowed = false,
this.isPip = false,
});
Widget _withControlsAreaTap(Widget child) {
final onTap = onControlsAreaTap;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap ?? () {},
child: child,
);
}
Widget _withTopDragHandle(Widget child) {
if (isPip) {
return DragToMoveArea(child: child);
}
return TopDragArea(enabled: isWindowed, child: child);
}
@override
Widget build(BuildContext context) {
final tokens = context.appTokens;
return IgnorePointer(
ignoring: !visible,
child: AnimatedOpacity(
opacity: visible ? 1 : 0,
duration: const Duration(milliseconds: 160),
child: Stack(
fit: StackFit.expand,
children: [
Positioned(
left: 0,
top: 0,
right: 0,
child: MouseRegion(
onEnter: (_) => onControlsHoverChanged?.call(true),
onExit: (_) => onControlsHoverChanged?.call(false),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {},
child: DecoratedBox(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.black87, Colors.transparent],
),
),
child: _withTopDragHandle(
Padding(
padding: EdgeInsets.fromLTRB(
topBarLeftInset,
topBarTopInset,
tokens.chromeInset,
isPip ? 12 : 28,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: topBar,
),
),
),
),
),
),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: MouseRegion(
onEnter: (_) => onControlsHoverChanged?.call(true),
onExit: (_) => onControlsHoverChanged?.call(false),
child: _withControlsAreaTap(
Container(
padding: EdgeInsets.fromLTRB(
0,
isPip ? 8 : 20,
0,
isPip ? 6 : 8,
),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [Colors.black87, Colors.transparent],
),
),
child: bottomBar,
),
),
),
),
if (leftBar != null)
Positioned(
left: 28,
top: 0,
bottom: 0,
child: Center(child: leftBar!),
),
if (rightBar != null)
Positioned(
right: 16,
top: 0,
bottom: 0,
child: Center(child: rightBar!),
),
if (centerBar != null)
Positioned.fill(
child: Center(
child: MouseRegion(
onEnter: (_) => onControlsHoverChanged?.call(true),
onExit: (_) => onControlsHoverChanged?.call(false),
child: centerBar!,
),
),
),
],
),
),
);
}
}