完善音频播放器

This commit is contained in:
wangyu 2026-03-20 09:48:57 +08:00
parent 4a30c53eda
commit 4af7f394cf
5 changed files with 7 additions and 250 deletions

View File

@ -134,11 +134,6 @@ export class RouterUrls {
*/
static readonly VIDEO_PLAYER_PAGE = "pages/video/VideoPlayerPage"
/**
* 音频播放页
*/
static readonly AUDIO_PLAYER_PAGE = "pages/audio/AudioPlayerPage"
/**
* 图片查看页
*/

View File

@ -178,7 +178,8 @@ export struct AudioPlayerDialog {
Image(this.index > 0 ? $r('app.media.ic_last_audio_enable') : $r('app.media.ic_last_audio_disable')).width(20).height(20)
.onClick(async () => {
if (this.index > 0) {
await this.avPlayer!!.stop()
await this.avPlayer!!.pause()
await this.avPlayer!!.reset()
this.index--
this.uri = this.mediaList[this.index].uri
this.title = this.mediaList[this.index].name
@ -189,7 +190,6 @@ export struct AudioPlayerDialog {
}
}
})
.visibility(Visibility.None)
Image(this.isPlaying ? $r('app.media.ic_audio_pause') : $r('app.media.ic_audio_play')).width(30).height(30)
.margin({left: 50, right: 50})
@ -206,7 +206,8 @@ export struct AudioPlayerDialog {
.rotate({angle: 180})
.onClick(async () => {
if (this.index < this.mediaList.length - 1) {
await this.avPlayer!!.stop()
await this.avPlayer!!.pause()
await this.avPlayer!!.reset()
this.index++
this.uri = this.mediaList[this.index].uri
this.title = this.mediaList[this.index].name
@ -217,7 +218,6 @@ export struct AudioPlayerDialog {
}
}
})
.visibility(Visibility.None)
}
.width('100%')
.justifyContent(FlexAlign.Center)

View File

@ -1,237 +0,0 @@
import { TipDialog } from '../../dialog/TipDialog'
import { ShareManager } from '../../manager/ShareManager'
import { TitleBar } from '../../view/TitleBar'
import { ToastUtils } from '../../utils/ToastUtils'
import { AppUtil } from '@pura/harmony-utils'
import { EventConstants } from '../../common/EventConstants'
import { MediaAction, MediaType } from '../../manager/MediaManager'
import { media } from '@kit.MediaKit'
import { fileIo } from '@kit.CoreFileKit'
import { LocalMediaManager } from '../../manager/LocalMediaManager'
import { avSessionManager } from '../../manager/AVSessionManager'
@Entry
@ComponentV2
struct AudioPlayerPage {
@Local title: string = ''
@Local uri: string = ''
@Local showActions: boolean = false
@Local currentTime: number = 0
@Local durationTime: number = 0
@Local isPlaying: boolean = false
avPlayer?: media.AVPlayer;
aboutToAppear(): void {
this.initParams()
this.initPlayer()
}
onPageHide(): void {
if (this.avPlayer) {
this.avPlayer.pause()
}
}
aboutToDisappear(): void {
if (this.avPlayer) {
this.avPlayer.release()
}
}
initParams() {
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>;
if (params) {
this.title = params.title as string
this.uri = params.uri as string;
this.showActions = params.showActions as boolean
}
}
async initPlayer() {
this.avPlayer = await media.createAVPlayer();
// 创建状态机变化回调函数
this.setAVPlayerCallback();
// 打开相应的资源文件地址获取fd
let file = await fileIo.open(this.uri);
this.avPlayer.url = 'fd://' + file.fd;
}
formatTime(time: number): string {
let minute: number = 0
let second: number = 0
if (time > 60) {
minute = Math.trunc(time / 60)
second = time % 60
if (minute < 10) {
if (second < 10) {
return `0${minute}:0${second}`
} else {
return `0${minute}:${second}`
}
} else {
if (second < 10) {
return `${minute}:0${second}`
} else {
return `${minute}:${second}`
}
}
} else {
second = time
if (second < 10) {
return `00:0${second}`
} else {
return `00:${second}`
}
}
}
// 注册avplayer回调函数
setAVPlayerCallback() {
this.avPlayer!!.on('error', (err) => {
console.error(`播放器发生错误,错误码:${err.code}, 错误信息:${err.message}`);
// 调用reset重置资源触发idle状态
this.isPlaying = false
this.avPlayer!!.reset();
avSessionManager.deactivate()
})
// 状态机变化回调函数
this.avPlayer!!.on('stateChange', async (state, reason) => {
switch (state) {
case 'initialized':
console.info('资源初始化完成');
// 资源初始化完成,开始准备文件
this.avPlayer!!.prepare();
break;
case 'prepared':
console.info('资源准备完成');
// 资源准备完成,开始准备文件
this.durationTime = Math.trunc(this.avPlayer!!.duration / 1000)
this.currentTime = this.avPlayer!!.currentTime;
await avSessionManager.activate()
this.avPlayer!!.play();
break;
case 'completed':
console.info('播放完成');
this.isPlaying = false
this.avPlayer!!.off('bufferingUpdate')
AppStorage.setOrCreate('currentTime', this.durationTime);
avSessionManager.deactivate()
break;
case 'playing':
console.info('播放开始');
this.isPlaying = true
break;
case 'released':
case 'stopped':
case 'error':
case 'paused':
console.info('播放暂停');
this.isPlaying = false
avSessionManager.deactivate()
break;
}
})
// 时间上报监听函数
this.avPlayer!!.on('timeUpdate', (time: number) => {
this.currentTime = Math.trunc(time / 1000);
});
}
build() {
Column() {
TitleBar().width('100%')
RelativeContainer() {
Image($r('app.media.ic_audio_thumb'))
Row() {
Image(this.isPlaying ? $r('app.media.ic_player_controls_pause') : $r('app.media.ic_player_controls_play'))
.width(20)
.height(20)
.margin({ right: 20 })
.onClick(async () => {
if (this.isPlaying) {
this.avPlayer!!.pause()
} else {
await avSessionManager.activate()
this.avPlayer!!.play()
}
})
Text(this.formatTime(this.currentTime)).width(35).fontColor(Color.White).fontSize(12)
Slider({
value: this.currentTime,
min: 0,
max: this.durationTime
})
.blockColor(Color.White)
.trackColor($r('app.color.color_60ffffff'))
.onChange((value: number, mode: SliderChangeMode) => {
this.avPlayer!!.seek(value * 1000, 2); // 设置视频播放的进度跳转到value处
this.currentTime = value;
})
.layoutWeight(1)
Text(this.formatTime(this.durationTime)).width(35).fontColor(Color.White).fontSize(12)
}
.opacity(0.8)
.width("100%")
.padding({ left: 30, right: 30 })
.margin({ bottom: this.showActions ? 0 : 50})
.alignRules({
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
})
}.layoutWeight(1)
Row() {
Column() {
Image($r('app.media.ic_action_share')).width(50).height(50)
Text('转发').fontSize(12).fontColor($r('app.color.color_50ffffff')).margin({ top: 13 })
}
.id('btn_share')
.alignRules({
right: { anchor: '__container__', align: HorizontalAlign.Center }
})
.margin({ right: 40 })
.onClick(() => {
ShareManager.shareFile(this.uri)
})
Column() {
Image($r('app.media.ic_action_delete')).width(50).height(50)
Text('删除').fontSize(12).fontColor($r('app.color.color_50ffffff')).margin({ top: 13 })
}
.id('btn_delete')
.alignRules({
left: { anchor: '__container__', align: HorizontalAlign.Center },
})
.margin({ left: 40 })
.onClick(() => {
this.avPlayer!!.pause()
TipDialog.show(this.getUIContext(), {
title: '提示', content: '确定删除该音频?', callback: {
confirm: () => {
fileIo.unlink(this.uri)
.then(() => {
ToastUtils.show('删除成功')
LocalMediaManager.delete(this.title)
AppUtil.getContext().eventHub.emit(EventConstants.MediaActionEvent, MediaType.AUDIO, MediaAction.DELETE)
this.getUIContext().getRouter().back()
})
.catch(() => {
ToastUtils.show('删除失败, 请到文件管理中手动删除')
})
}
}
})
})
}
.height(200)
.margin({ top: 10 })
.visibility(this.showActions ? Visibility.Visible : Visibility.None)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.window_background'))
}
}

View File

@ -23,13 +23,12 @@ import { AudioRecordPage } from './record/AudioRecordPage';
@ComponentV2
export struct MinePage {
@Local showChallenge: boolean = false;
@Local showShare: boolean = false;
@Local isLogin: boolean = LoginManager.isLogin();
@Local userinfo?: UserEntity;
@Local diamondInfo?: DiamondDetailEntity
@Local currentIndex: number = 0;
@Local tabBarModifier: CommonModifier = new CommonModifier()
@Local menuList: Array<MenuEntity> = []
private viewModel: MineViewModel = new MineViewModel(this.getUIContext());
@ -41,6 +40,7 @@ export struct MinePage {
@Monitor('viewModel.userEntity')
onUserinfoChange(monitor: IMonitor) {
this.userinfo = monitor.value()?.now as UserEntity;
this.menuList = mineMenuList().convertToArray()
}
@Monitor('viewModel.wxService')
@ -287,7 +287,7 @@ export struct MinePage {
Text('常用工具').fontColor($r('app.color.color_212226')).fontSize(16).fontWeight(FontWeight.Medium).margin({top: 20})
Grid() {
ForEach(mineMenuList().convertToArray(), (item: MenuEntity) => {
ForEach(this.menuList, (item: MenuEntity) => {
GridItem() {
Column() {
Image(item.icon)

View File

@ -28,7 +28,6 @@
"pages/main/mine/setting/account/BindAccountPage",
"pages/main/mine/setting/account/ManageAccountPage",
"pages/video/VideoPlayerPage",
"pages/audio/AudioPlayerPage",
"pages/photo/PhotoViewPage"
]
}