buildBottomBarSlot function

Widget buildBottomBarSlot(
  1. SlotBuildContext ctx,
  2. double width,
  3. double height
)

构建底部栏插槽的默认实现。 Builds the default bottom bar slot content.

监听播放状态、进度、缓冲、总时长、字幕等状态变化, 提供完整的底部播放控制栏 UI。

Listens to play state, position, buffering, duration, and subtitle state; provides the full bottom playback control bar UI.

Implementation

Widget buildBottomBarSlot(
  SlotBuildContext ctx,
  double width,
  double height,
) {
  // 监听播放状态、当前播放位置、缓冲位置、总时长、场景类型等
  final listenable = Listenable.merge([
    ctx.controller.playStateNotifier,
    ctx.controller.currentPositionNotifier,
    ctx.controller.bufferedPositionNotifier,
    ctx.controller.totalDurationNotifier,
    ctx.controller.externalSubtitleAvailableNotifier,
    ctx.controller.showExternalSubtitleNotifier,
    ctx.controller.sceneTypeNotifier,
  ]);

  return ListenableBuilder(
    listenable: listenable,
    builder: (context, _) {
      final sceneType = ctx.controller.sceneTypeNotifier.value;
      final enableDrag = isNotSceneType(sceneType, [
        SceneType.live,
        SceneType.restricted,
      ]);
      final enableSeek = isNotSceneType(sceneType, [
        SceneType.live,
        SceneType.restricted,
      ]);

      // 获取播放状态
      final playState = ctx.controller.playStateNotifier.value;
      // 获取当前播放位置、缓冲位置、总时长
      final currentPosition = ctx.controller.currentPositionNotifier.value;
      final bufferedPosition = ctx.controller.bufferedPositionNotifier.value;
      final totalDuration = ctx.controller.totalDurationNotifier.value;
      // 初始化章节信息(章节数需 >= 2 才展示)
      final chapters = ctx.controller.widgetData?.chapters ?? const [];
      final chapterInfoList =
          chapters.length >= 2 ? chapters : const <ChapterInfo>[];

      return BottomBarWidget(
        animationManager: ctx.animationManager,
        controller: ctx.controller,
        sceneType: sceneType,
        chapterInfoList: chapterInfoList,
        orientation: MediaQuery.of(context).orientation,
        isPlaying: playState == FlutterAvpdef.started,
        currentPosition: currentPosition,
        bufferedPosition: bufferedPosition,
        totalDuration: totalDuration,
        onPlayIconPressed: () {
          if (ctx.controller.isDraggingNotifier.value) return;
          final wasVisible = ctx.animationManager.isVisible;
          ctx.animationManager.toggle();
          ctx.controller.controlBarVisibleNotifier.value = !wasVisible;
          ctx.controller.togglePlayState();
        },
        onReplayIconPressed: ctx.controller.replay,
        onFullScreenPressed: ctx.controller.toggleFullscreen,
        onSubtitlePressed: () => _toggleSubtitleShow(
          context,
          ctx.controller,
        ),
        onDragUpdate:
            enableDrag ? (duration) => _onDragUpdate(ctx, duration) : null,
        onDragEnd: enableDrag ? (duration) => _onDragEnd(ctx, duration) : null,
        onSeekEnd:
            enableSeek ? (duration) => ctx.controller.seek(duration) : null,
        isShowExternalSubtitle:
            ctx.controller.showExternalSubtitleNotifier.value,
        isShowExternalSubtitleBtn:
            ctx.controller.externalSubtitleAvailableNotifier.value,
      );
    },
  );
}