diff --git a/lib/screens/layouts/video_status_label.dart b/lib/screens/layouts/video_status_label.dart index 6263a956..fcc275c4 100644 --- a/lib/screens/layouts/video_status_label.dart +++ b/lib/screens/layouts/video_status_label.dart @@ -122,9 +122,13 @@ class _VideoStatusLabelState extends State { ? position.dy - height - padding : position.dy + boxSize.height + padding; + final overflowsRight = left + width > constraints.maxWidth; + final right = constraints.maxWidth - position.dx - boxSize.width; + return Stack(children: [ Positioned( - left: left, + left: overflowsRight ? null : left, + right: overflowsRight ? right : null, top: top, height: height, width: width, diff --git a/lib/screens/players/live_player.dart b/lib/screens/players/live_player.dart index 2d60919b..6ecd14f4 100644 --- a/lib/screens/players/live_player.dart +++ b/lib/screens/players/live_player.dart @@ -319,6 +319,8 @@ class __DesktopLivePlayerState extends State<_DesktopLivePlayer> { late StreamSubscription _volumeStreamSubscription; double get volume => widget.player.volume; + final _videoViewKey = GlobalKey(); + @override void initState() { super.initState(); @@ -344,6 +346,59 @@ class __DesktopLivePlayerState extends State<_DesktopLivePlayer> { WindowButtons( title: widget.device.fullName, showNavigator: false, + flexible: Row(children: [ + if (widget.device.hasPTZ) + SquaredIconButton( + icon: Icon( + Icons.videogame_asset, + color: ptzEnabled ? Colors.white : null, + shadows: outlinedText(), + ), + tooltip: ptzEnabled ? loc.enabledPTZ : loc.disabledPTZ, + onPressed: () => setState(() => ptzEnabled = !ptzEnabled), + ), + () { + final isMuted = widget.player.volume == 0.0; + + return SquaredIconButton( + icon: Icon( + isMuted ? Icons.volume_mute_rounded : Icons.volume_up_rounded, + shadows: outlinedText(), + color: Colors.white, + ), + tooltip: isMuted ? loc.enableAudio : loc.disableAudio, + onPressed: () async { + if (isMuted) { + await widget.player.setVolume(1.0); + } else { + await widget.player.setVolume(0.0); + } + }, + ); + }(), + if (isDesktopPlatform && !isSubView) + SquaredIconButton( + icon: Icon( + Icons.open_in_new, + shadows: outlinedText(), + color: Colors.white, + ), + tooltip: loc.openInANewWindow, + onPressed: widget.device.openInANewWindow, + ), + CameraViewFitButton( + fit: fit, + onChanged: (newFit) => setState(() => fit = newFit), + ), + const SizedBox(width: 8.0), + if (_videoViewKey.currentContext != null) + VideoStatusLabel( + device: widget.device, + video: UnityVideoView.of(_videoViewKey.currentContext!), + position: VideoStatusLabelPosition.top, + ), + const SizedBox(width: 8.0), + ]), ), Expanded( child: PTZController( @@ -356,7 +411,7 @@ class __DesktopLivePlayerState extends State<_DesktopLivePlayer> { player: widget.player, fit: fit, paneBuilder: (context, player) { - return Stack(children: [ + return Stack(key: _videoViewKey, children: [ if (commands.isNotEmpty) PTZData(commands: commands), Positioned.fill( child: Center( @@ -384,70 +439,6 @@ class __DesktopLivePlayerState extends State<_DesktopLivePlayer> { ), ), ), - PositionedDirectional( - bottom: 8.0, - end: 8.0, - start: 8.0, - child: Row(children: [ - if (widget.device.hasPTZ) - SquaredIconButton( - icon: Icon( - Icons.videogame_asset, - color: ptzEnabled ? Colors.white : null, - shadows: outlinedText(), - ), - tooltip: - ptzEnabled ? loc.enabledPTZ : loc.disabledPTZ, - onPressed: () => - setState(() => ptzEnabled = !ptzEnabled), - ), - const Spacer(), - () { - final isMuted = widget.player.volume == 0.0; - - return SquaredIconButton( - icon: Icon( - isMuted - ? Icons.volume_mute_rounded - : Icons.volume_up_rounded, - shadows: outlinedText(), - color: Colors.white, - ), - tooltip: isMuted ? loc.enableAudio : loc.disableAudio, - onPressed: () async { - if (isMuted) { - await widget.player.setVolume(1.0); - } else { - await widget.player.setVolume(0.0); - } - }, - ); - }(), - if (isDesktopPlatform && !isSubView) - SquaredIconButton( - icon: Icon( - Icons.open_in_new, - shadows: outlinedText(), - color: Colors.white, - ), - tooltip: loc.openInANewWindow, - onPressed: () { - widget.device.openInANewWindow(); - }, - ), - CameraViewFitButton( - fit: fit, - onChanged: (newFit) { - setState(() => fit = newFit); - }, - ), - const SizedBox(width: 8.0), - VideoStatusLabel( - device: widget.device, - video: UnityVideoView.of(context), - ), - ]), - ), ]); }, ); diff --git a/lib/widgets/desktop_buttons.dart b/lib/widgets/desktop_buttons.dart index 271312ac..e35e30b8 100644 --- a/lib/widgets/desktop_buttons.dart +++ b/lib/widgets/desktop_buttons.dart @@ -86,6 +86,7 @@ class WindowButtons extends StatelessWidget { this.title, this.showNavigator = true, this.onBack, + this.flexible, }); /// The current window title. @@ -104,6 +105,9 @@ class WindowButtons extends StatelessWidget { /// Called when the back button is pressed. final Future Function()? onBack; + /// The widget displayed in the remaining space. + final Widget? flexible; + @override Widget build(BuildContext context) { if (!isDesktop || isMobile) return const SizedBox.shrink(); @@ -240,6 +244,8 @@ class WindowButtons extends StatelessWidget { icon: const Icon(Icons.refresh, size: 20.0), tooltip: loc.refresh, ), + if (flexible != null) flexible!, + // Do not render the Window Buttons on web nor macOS. macOS // render the buttons natively. if (!kIsWeb && !isMacOSPlatform && !UpdateManager.isEmbedded)