part of 'player_page.dart'; extension _PlayerPageOverlays on _PlayerPageState { List _buildVideoOverlays(PlaybackSession session) { return [ Positioned( top: 20, left: 0, right: 0, bottom: 0, child: ValueListenableBuilder( valueListenable: _danmakuOverlayVersion, builder: (context, value, child) { if (!_danmakuLoaded || !_panelSettings.enabled) { return const SizedBox.shrink(); } return IgnorePointer( child: ValueListenableBuilder( valueListenable: _bufferingOverlayVisible, builder: (context, buffering, child) { return Opacity(opacity: buffering ? 0.0 : 1.0, child: child); }, child: LayoutBuilder( builder: (context, constraints) { final screenHeight = constraints.maxHeight.isFinite ? constraints.maxHeight : null; _danmakuOverlayHeight = screenHeight; final option = _buildDanmakuOption(_panelSettings); if (screenHeight != null && (screenHeight != _danmakuOverlaySyncedHeight || !identical( _panelSettings, _danmakuOverlaySyncedSettings, ))) { _danmakuOverlaySyncedHeight = screenHeight; _danmakuOverlaySyncedSettings = _panelSettings; WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; _feeder.setPanelSettings( _panelSettings, option: _buildDanmakuOption(_panelSettings), ); }); } return DanmakuScreen( option: option, createdController: (c) { _feeder.attach(c); _feeder.setPanelSettings( _panelSettings, option: option, ); final pos = session.engine.state.position; _syncDanmakuFeederForSession( _feeder, session, pos.inMilliseconds / 1000.0, ); }, ); }, ), ), ); }, ), ), Positioned.fill( child: ValueListenableBuilder( valueListenable: _subtitleOverlayVersion, builder: (context, value, child) { return StyledSubtitleOverlay( player: session.engine, settings: _subtitleSettings, externalLines: session.externalSubtitleLines, externalActive: session.activeExternalSubtitle, ); }, ), ), Positioned.fill( child: BufferingOverlay( player: session.engine, speedMonitor: session.speedMonitor, suppress: _switchInFlight, onBufferingChanged: (value) { if (mounted) _bufferingOverlayVisible.value = value; }, ), ), ValueListenableBuilder( valueListenable: _debugHudVisible, builder: (context, visible, _) { if (!visible) return const SizedBox.shrink(); return PlayerDebugHud( engine: session.engine, frameMonitor: _frameJankMonitor, ); }, ), ]; } List _buildPipOverlays(PlaybackSession session) { return [ Positioned.fill( child: BufferingOverlay( player: session.engine, speedMonitor: session.speedMonitor, onBufferingChanged: (value) { if (mounted) _bufferingOverlayVisible.value = value; }, ), ), ]; } }