fix: Adjust subtitle offset to avoid overlap with visible menu

This commit is contained in:
Kirill Boychenko 2025-07-28 00:17:03 +02:00
parent c7afade615
commit b9f87bbc5e
2 changed files with 192 additions and 150 deletions

View file

@ -288,8 +288,12 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
); );
} }
final GlobalKey _bottomControlsKey = GlobalKey();
Widget bottomButtons(BuildContext context) { Widget bottomButtons(BuildContext context) {
return Consumer(builder: (context, ref, child) { return Container(
key: _bottomControlsKey,
child: Consumer(builder: (context, ref, child) {
final mediaPlayback = ref.watch(mediaPlaybackProvider); final mediaPlayback = ref.watch(mediaPlaybackProvider);
final bitRateOptions = ref.watch(playBackModel.select((value) => value?.bitRateOptions)); final bitRateOptions = ref.watch(playBackModel.select((value) => value?.bitRateOptions));
return Container( return Container(
@ -390,7 +394,8 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
Tooltip( Tooltip(
message: context.localized.stop, message: context.localized.stop,
child: IconButton( child: IconButton(
onPressed: () => closePlayer(), icon: const Icon(IconsaxPlusLinear.close_square))), onPressed: () => closePlayer(),
icon: const Icon(IconsaxPlusLinear.close_square))),
const Spacer(), const Spacer(),
if (AdaptiveLayout.viewSizeOf(context) >= ViewSize.tablet && if (AdaptiveLayout.viewSizeOf(context) >= ViewSize.tablet &&
ref.read(videoPlayerProvider).hasPlayer) ...{ ref.read(videoPlayerProvider).hasPlayer) ...{
@ -430,7 +435,13 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
), ),
), ),
); );
}); }));
}
// Method to get height
double? getMenuHeight() {
final RenderBox? renderBox = _bottomControlsKey.currentContext?.findRenderObject() as RenderBox?;
return renderBox?.size.height;
} }
Widget progressBar(MediaPlaybackModel mediaPlayback) { Widget progressBar(MediaPlaybackModel mediaPlayback) {

View file

@ -196,6 +196,7 @@ class LibMPV extends BasePlayer {
class _VideoSubtitles extends ConsumerStatefulWidget { class _VideoSubtitles extends ConsumerStatefulWidget {
final VideoController controller; final VideoController controller;
final bool showOverlay; final bool showOverlay;
const _VideoSubtitles({ const _VideoSubtitles({
required this.controller, required this.controller,
this.showOverlay = false, this.showOverlay = false,
@ -211,12 +212,14 @@ class _VideoSubtitlesState extends ConsumerState<_VideoSubtitles> {
@override @override
void initState() { void initState() {
super.initState();
subscription = widget.controller.player.stream.subtitle.listen((value) { subscription = widget.controller.player.stream.subtitle.listen((value) {
if (mounted) {
setState(() { setState(() {
subtitle = value; subtitle = value;
}); });
}
}); });
super.initState();
} }
@override @override
@ -225,24 +228,52 @@ class _VideoSubtitlesState extends ConsumerState<_VideoSubtitles> {
super.dispose(); super.dispose();
} }
/// Calculate subtitle offset based on menu visibility
double _calculateSubtitleOffset(SubtitleSettingsModel settings) {
if (!widget.showOverlay) {
return settings.verticalOffset;
}
// Estimate the menu area (bottom ~15% of screen typically contains controls)
const menuAreaThreshold = 0.15;
// If subtitles are already positioned above the menu area, leave them alone
if (settings.verticalOffset >= menuAreaThreshold) {
return settings.verticalOffset;
}
// When menu is visible and subtitles are in the menu area,
// move them up slightly to avoid overlap
const menuAvoidanceOffset = 0.1;
final adjustedOffset = settings.verticalOffset + menuAvoidanceOffset;
// Clamp to reasonable bounds (don't go too high or too low)
return math.min(adjustedOffset, 0.85); // Max 85% up from bottom
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settings = ref.watch(subtitleSettingsProvider); final settings = ref.watch(subtitleSettingsProvider);
final padding = MediaQuery.of(context).padding; final padding = MediaQuery.of(context).padding;
final text = [
for (final line in subtitle)
if (line.trim().isNotEmpty) line.trim(),
].join('\n');
// Process subtitle text
final text = subtitle.where((line) => line.trim().isNotEmpty).map((line) => line.trim()).join('\n');
// Return empty widget if libass is enabled (native subtitle rendering)
if (widget.controller.player.platform?.configuration.libass ?? false) { if (widget.controller.player.platform?.configuration.libass ?? false) {
return const IgnorePointer(child: SizedBox.shrink()); return const IgnorePointer(child: SizedBox.shrink());
} else { }
// Return empty widget if no subtitle text
if (text.isEmpty) {
return const IgnorePointer(child: SizedBox.shrink());
}
return SubtitleText( return SubtitleText(
subModel: settings, subModel: settings,
padding: padding, padding: padding,
offset: settings.verticalOffset, // Always use user's preferred position offset: _calculateSubtitleOffset(settings),
text: text, text: text,
); );
} }
} }
}