import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:new_learn/core/components/audio_player_card.dart'; /// ============================================================ /// 【AudioPlayerDemoPage】音频播放 Demo(just_audio 控制条组件) /// /// 一、本页解决什么问题: /// 展示 AudioPlayerCard 的用法:传 asset 即可得到一个 /// 完整的音频控制条(播放/暂停、进度拖动、倍速、循环)。 /// /// 二、音频源说明: /// 用【本地 assets 音频】做 demo:本地文件 seek 跳播无需重新缓冲, /// 进度条拖动秒响应(在线流 seek 会重新缓冲,见组件文档"高频坑")。 /// 以后接真实课程音频时,把 asset 换成 url 传后端在线地址即可。 /// /// 三、高频坑: /// 1. AudioPlayerCard 只是"控制条",不是整页 —— 它设计成可嵌进 /// 任意列表/详情页(如课程详情里的音频小节); /// 2. 切后台会自动暂停(组件内部处理),无需业务页操心; /// 3. 若要"列表连续播放",后面在 AudioPlayerCard 上加 /// setAudioSources + 上一首/下一首即可(just_audio 原生支持); /// 4. 网络流 seek 后会有一次"缓冲中 X%"(进度条浅色区域 = 已缓冲), /// 这是 ExoPlayer 的正常机制,不是卡死。 /// ============================================================ class AudioPlayerDemoPage extends StatelessWidget { const AudioPlayerDemoPage({super.key}); /// 本地测试音频(30 秒,来自 assets/audio/sample-30s.mp3) // static const String _audioAsset = 'assets/audio/sample-30s.mp3'; /// 【临时调试】网络源:观察 seek 后进度条的"缓冲区域 + 缓冲中 X%"。 /// ⚠ 踩坑:之前用 samplelib.com —— 实测它的服务器【不支持 HTTP Range】 /// (Range 请求返回 200 而非 206),导致:第一次点进度条中间段, /// ExoPlayer 无法字节定位 → 位置被重置回起点;第二次打开因为有系统 /// 缓存 → 看似正常(会误导排查方向!)。 /// 现用 SoundHelix(curl 实测 206 Partial Content + Accept-Ranges: bytes), /// 服务器在境外,网络慢 = 缓冲条涨得慢看得清,正好演示缓冲机制。 /// 以后接自己的课程音频,务必先验收服务器支持 Range: /// curl -s -D - -o NUL -H "Range: bytes=0-1023" <音频url> /// 看到 HTTP/1.1 206 Partial Content 才算支持 seek 跳播。 static const String _audioUrl = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3'; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('音频播放'), centerTitle: true, ), body: Padding( padding: EdgeInsets.all(16.w), child: Column( children: [ // 音频控制条 // 【临时调试】切网络源看缓冲条;要回本地源时取消下面注释 // 并把上面的 url 改回 asset。 // const AudioPlayerCard( // asset: _audioAsset, // title: '本地测试音频(30 秒)', // autoPlay: true, // ), const AudioPlayerCard( url: _audioUrl, title: '网络测试音频(约 6 分钟)', autoPlay: true, ), SizedBox(height: 20.h), const Text( '支持:播放/暂停、进度拖动(本地秒响应)、倍速切换、循环;\n切后台自动暂停;全部通过 props 配置。', textAlign: TextAlign.center, style: TextStyle(fontSize: 13, color: Color(0xFF999999)), ), ], ), ), ); } }