section_page.dart 13.8 KB
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:nested_scroll_views/material.dart';
import 'package:wow_english/common/core/user_util.dart';
import 'package:wow_english/common/utils/click_with_music_controller.dart';
import 'package:wow_english/models/course_unit_entity.dart';
import 'package:wow_english/pages/section/section_type.dart';
import 'package:wow_english/pages/section/widgets/section_item.dart';
import 'package:wow_english/pages/section/widgets/section_bouns_item.dart';
import 'package:wow_english/pages/section/widgets/section_header_widget.dart';
import 'package:wow_english/route/route.dart';
import 'package:wow_english/utils/audio_player_util.dart';
import 'package:wow_english/utils/toast_util.dart';

import '../../models/course_section_entity.dart';
import '../../utils/log_util.dart';
import 'bloc/section_bloc.dart';
import 'courese_module_model.dart';

/// 环节(课程)列表页
class SectionPage extends StatelessWidget {
  const SectionPage(
      {super.key, required this.courseUnitEntity, required this.courseUnitId});

  final CourseUnitEntity courseUnitEntity;

  /// unitId
  final int courseUnitId;

  @override
  Widget build(BuildContext context) {
    int initialPage = courseUnitEntity.courseUnitVOList
            ?.indexWhere((element) => element.id == courseUnitId) ??
        0;
    return BlocProvider(
      create: (context) => SectionBloc(
          courseUnitEntity,
          initialPage,
          PageController(initialPage: initialPage),
          ScrollController(),
          ScrollController())
        ..add(InitEvent()),
      //为了触发指示器进入后计算位置
      //   ..add(CurrentUnitIndexChangeEvent(initialPage)),
      child: _SectionPageView(context),
    );
  }
}

class _SectionPageView extends StatelessWidget {
  const _SectionPageView(this.context);

  final BuildContext context;

  @override
  Widget build(BuildContext context) {
    final bloc = BlocProvider.of<SectionBloc>(context);
    final clickController = ClickWithMusicController.instance;
    return BlocListener<SectionBloc, SectionState>(
      listener: (context, state) async {
        if (state is RequestEnterClassState) {
          final courseType = state.courseType;
          final courseLessonId = state.courseLessonId;
          if (courseType == SectionType.song.value ||
              courseType == SectionType.video.value) {
            final title =
                courseType == SectionType.song.value ? 'song' : 'video';
            final AudioPlayerUtilType audioType;

            ///儿歌/视频类型
            if (courseType == SectionType.song.value) {
              audioType = AudioPlayerUtilType.musicTime;
            } else {
              audioType = AudioPlayerUtilType.videoTime;
            }

            clickController.playMusicAndPerformAction(context, audioType,
                () async {
              ///播放音乐->调进入课程接口->跳转课程页面
              await bloc.requestEnterClass(courseLessonId, () {
                Log.d("WQF request finish");
                pushNamed(AppRouteName.lookVideo, arguments: {
                  'videoUrl': null,
                  'title': title,
                  'courseLessonId': courseLessonId,
                  'isTopic': true
                }).then((value) {
                  if (value != null) {
                    Map<String, dynamic> dataMap =
                        value as Map<String, dynamic>;
                    bloc.add(RequestEndClassEvent(
                        dataMap['courseLessonId']!, dataMap['isCompleted'],
                        currentTime: dataMap['currentTime'],
                        autoNextSection: dataMap['nextSection']));
                  }
                  AudioPlayerUtil.getInstance()
                      .playAudio(AudioPlayerUtilType.countWithMe);
                });
              }, onRequestEnterFailed: (error) {
                Log.d("WQF requestEnterClass failed $error");
              });
            });
            return;
          }

          if (courseType == SectionType.pictureBook.value) {
            //绘本
            clickController.playMusicAndPerformAction(
                context, AudioPlayerUtilType.readingTime, () async {
              await bloc.requestEnterClass(courseLessonId, () {
                pushNamed(AppRouteName.reading,
                        arguments: {'courseLessonId': courseLessonId})
                    .then((value) {
                  if (value != null) {
                    Map<String, dynamic> dataMap =
                        value as Map<String, dynamic>;
                    bloc.add(RequestEndClassEvent(
                      dataMap['courseLessonId']!,
                      dataMap['isCompleted'],
                      currentStep: dataMap['currentStep'],
                      autoNextSection: dataMap['nextSection'],
                    ));
                    AudioPlayerUtil.getInstance()
                        .playAudio(AudioPlayerUtilType.countWithMe);
                  }
                });
              });
            });
            return;
          }

          if (courseType == SectionType.practice.value) {
            //练习
            clickController.playMusicAndPerformAction(
                context, AudioPlayerUtilType.quizTime, () async {
              await bloc.requestEnterClass(courseLessonId, () {
                pushNamed(AppRouteName.topicPic, arguments: {
                  'courseLessonId': courseLessonId,
                  'moduleColor': CourseModuleModel(
                          bloc.courseUnitEntity.courseModuleCode ?? 'Phase-1')
                      .color
                }).then((value) {
                  if (value != null) {
                    Map<String, dynamic> dataMap =
                        value as Map<String, dynamic>;
                    bloc.add(RequestEndClassEvent(
                        dataMap['courseLessonId']!, dataMap['isCompleted'],
                        currentStep: dataMap['currentStep'],
                        autoNextSection: dataMap['nextSection']));
                  }
                  AudioPlayerUtil.getInstance()
                      .playAudio(AudioPlayerUtilType.countWithMe);
                });
              });
            });
            return;
          }
        }
      },
      child: _sectionView(),
    );
  }

  Widget _sectionView() =>
      BlocBuilder<SectionBloc, SectionState>(builder: (context, state) {
        final bloc = BlocProvider.of<SectionBloc>(context);
        return Scaffold(
          body: Container(
            color: Colors.white,
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  SectionHeaderWidget(
                      title: bloc.getCourseUnitDetail().name,
                      courseModuleCode: bloc.courseUnitEntity.courseModuleCode,
                      onBack: () {
                        popPage(data: {
                          'needRefresh': bloc.courseUnitEntityChanged,
                        });
                      }),
                  Expanded(
                      child: Padding(
                    padding: EdgeInsets.symmetric(horizontal: 10.w),
                    child: NestedPageView.builder(
                        itemCount: bloc.unlockPageCount(),
                        controller: bloc.pageController,
                        onPageChanged: (int index) {
                          bloc.add(CurrentUnitIndexChangeEvent(index));
                        },
                        itemBuilder: (context, index) {
                          return ScrollConfiguration(
                            ///去掉 Android 上默认的边缘拖拽效果
                            behavior: ScrollConfiguration.of(context)
                                .copyWith(overscroll: false),
                            child: _itemTransCard(
                                bloc.getCourseUnitDetail(pageIndex: index),
                                index,
                                context),
                          );
                        }),
                  )),
                  SafeArea(
                    child: SizedBox(
                        width: 210.w,
                        height: 40.h,
                        // child: OverflowBox(
                        //   maxWidth: 300, // 允许内容超出容器宽度
                        child: ListView.builder(
                            controller: bloc.indicatorSrollController,
                            scrollDirection: Axis.horizontal,
                            itemCount: bloc.unlockPageCount(),
                            itemBuilder: (context, index) {
                              bool isSelected = index == bloc.currentPage;
                              // 计算透明度,使得当前页的指示器不透明,两侧逐渐透明
                              double opacity = 0.25 +
                                  (1 - ((bloc.currentPage - index).abs() / 2)) *
                                      0.5;
                              // 限制透明度在 0.5 到 1.0 之间
                              opacity = opacity.clamp(0.25, 1.0);
                              return GestureDetector(
                                onTap: () => bloc.pageController.animateToPage(
                                    index,
                                    duration: const Duration(milliseconds: 60),
                                    curve: Curves.ease),
                                child: SizedBox(
                                  width: 30.0.w,
                                  height: 30.0.h,
                                  child: Padding(
                                    padding:
                                        EdgeInsets.all(isSelected ? 0.w : 5.w),
                                    child: Opacity(
                                      opacity: opacity,
                                      child: Container(
                                        alignment: Alignment.center,
                                        decoration: BoxDecoration(
                                          color: isSelected
                                              ? Colors.blue
                                              : Colors.grey,
                                          shape: BoxShape.circle,
                                        ),
                                        child: Text("${index + 1}",
                                            textAlign: TextAlign.center,
                                            style: TextStyle(
                                                color: Colors.white,
                                                fontSize:
                                                    isSelected ? 12.sp : 8.sp)),
                                      ),
                                    ),
                                  ),
                                ),
                              );
                            })),
                  ),
                  // )
                ],
              ),
            ),
          ),
        );
      });
}

Widget _itemTransCard(
    CourseUnitDetail courseUnitDetail, int pageIndex, BuildContext context) {
  final bloc = BlocProvider.of<SectionBloc>(context);
  List<CourseSectionEntity>? courseSectionEntities =
      bloc.courseSectionDatasMap[courseUnitDetail.id];
  if (courseSectionEntities == null) {
    bloc.add(RequestDataEvent(courseUnitDetail.id!));
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text(
            '暂无数据',
            style: TextStyle(fontSize: 24.0),
          ),
          const SizedBox(height: 16.0),
          // 间距
          CircularProgressIndicator(
              color: CourseModuleModel(
                      bloc.courseUnitEntity.courseModuleCode ?? 'Phase-1')
                  .color),
          // 加载动画
        ],
      ),
    );
  } else {
    return NestedListView.builder(
        itemCount: bloc.courseSectionDatasMap[courseUnitDetail.id]?.length ?? 0,
        scrollDirection: Axis.horizontal,
        itemBuilder: (BuildContext context, int index) {
          CourseSectionEntity sectionData = courseSectionEntities[index];
          if (sectionData.courseType == SectionType.bouns.value) {
            //彩蛋
            return GestureDetector(
              onTap: () {
                if (!UserUtil.isLogined()) {
                  pushNamed(AppRouteName.login);
                  return;
                }
                if (sectionData.lock == true) {
                  showToast('当前课程暂未解锁');
                  return;
                }

                ///进入课堂
                bloc.add(RequestEnterClassEvent(
                    sectionData.id.toString(), sectionData.courseType));
              },
              child: SectionBoundsItem(
                imageUrl: sectionData.coverUrl,
              ),
            );
          } else {
            return GestureDetector(
              onTap: () {
                if (!UserUtil.isLogined()) {
                  pushNamed(AppRouteName.login);
                  return;
                }
                if (sectionData.lock == true) {
                  showToast('当前课程暂未解锁');
                  return;
                }

                ///进入课堂
                bloc.add(RequestEnterClassEvent(
                    sectionData.id.toString(), sectionData.courseType));
              },
              child: SectionItem(
                courseModuleId: bloc.courseUnitEntity.courseModuleCode,
                lessons: sectionData,
              ),
            );
          }
        });
  }
}