鸿蒙音视频同播,全屏处理

4 阅读12分钟
import { LengthMetrics, promptAction, router } from '@kit.ArkUI';
import window from '@ohos.window';
import common from '@ohos.app.ability.common';
import { media } from '@kit.MediaKit';
import { levelComponent } from '../components/levelComponent'
import { WorkApi } from '../api/work'
import { DateUtil, StrUtil, ToastUtil } from '@pura/harmony-utils';
import { WorksDetail, ShowDetail } from '../model/Works'
import { AudioPlayer } from '../utils/AudioPlayer'
import { BusinessError, emitter } from '@kit.BasicServicesKit';
import { MediaService } from '@ohos/hearingplayer/src/main/ets/utils/MediaService';
import { faceDetector } from '@kit.CoreVisionKit';
import {
  BreakpointConstants,
  CertificateStudyDialog,
  CommentInputDialog,
  CommonApi,
  commonTs,
  dateUtil, FollowButton,
  paintByPoint,
  paintByPoint2X,
  PullUpLoadMoreComponents,
  replaceLpx2Vp,
  ShareDialog,
  SoundPlayer,
  VipImageView,
  WorkTextDubbing} from '@ohos/common'
import { CommonObj, FzWebview } from 'fzlibrary';
import { openBuyVip, openNeedVip, openVipAndBuy, openVipOrBuy } from '@ohos/hearingplayer/src/main/ets/module/Pops';
import { VajraApi } from '@ohos/vajra/src/main/ets/api/VajraApi';
import { CommentModel, reply } from '@ohos/vajra/src/main/ets/model/CommentModel';
import { CommentDetailParams } from './CommentDetailsPage';
import { it } from '@ohos/hypium';
import RdbUtils from '../utils/RdbUtils';
import { relationalStore } from '@kit.ArkData';
import text from '@ohos.graphics.text';
import { NewWorksListModel } from '../model/NewWorksListModel';
import { DubbingSentence } from '@ohos/dubbing/src/main/ets/viewmodel/VideoDetails';
import { getSecond } from '@ohos/common/src/main/ets/utils/TimeFormat';
import { webview } from '@kit.ArkWeb';
import { AbilityConstant, OpenLinkOptions } from '@kit.AbilityKit';
import { format } from '../utils/formart';
import { FZJSExportObjectOfVideo } from '@ohos/dubbing/src/main/ets/utils/FZJSExportObjectOfVideo';
import { ComposeAudioRet } from '@ohos/dubbing/src/main/ets/viewmodel/AudioBean';
import { AlbumApi } from '../api/album';
import { AlbumDetails } from '../model/Album';
import { image } from '@kit.ImageKit';
import { Certificate } from '@ohos/common/src/main/ets/model/CertificateBean';
import { ShareApi } from '@ohos/common/src/main/ets/api/ShareApi';
import { ShareData } from '@ohos/im_chat';


let isKeepScreenOn: boolean = true;

// let windowClass: window.Window = window.findWindow("test");
// try {
//   windowClass.setWindowKeepScreenOn(isKeepScreenOn, (err: BusinessError) => {
//     const errCode: number = err.code;
//     if (errCode) {
//       console.error('Failed to set the screen to be always on. Cause: ' + JSON.stringify(err));
//       return;
//
//     }
//     console.info('Succeeded in setting the screen to be always on.');
//   });
// } catch (exception) {
//   console.error('Failed to set the screen to be always on. Cause: ' + JSON.stringify(exception));
// }
// 进度条样式
@Extend(Slider)
function videoSlider() {
  .trackColor('#ffffff')
  .trackThickness(replaceLpx2Vp(5))
  .selectedColor('#2ACF6F')
  .blockBorderColor('rgba(44, 211, 215, 0.3)')
  .blockBorderWidth(replaceLpx2Vp(8))
  .blockColor('#2CD3D7')
  .blockSize({ width: replaceLpx2Vp(25), height: replaceLpx2Vp(25) })
}

@Extend(Image)
function imageWith(isFull:boolean,breakPoint:string){
  .width(isFull ? '18lpx' : breakPoint === BreakpointConstants.BREAKPOINT_MD ? '36lpx' : replaceLpx2Vp(36))
}

interface audioInfo {
  id: string,
  title: string,
  price: string,
  vip_price: string,
  uid: string,
}

class resultClass {
  id: number = 0;
  src: ResourceStr = '';
  title: string = '';
  desc: string = '';

  constructor(id: number, src: ResourceStr, title: string, desc: string) {
    this.id = id;
    this.src = src;
    this.title = title;
    this.desc = desc
  }
}

interface dubbingParams {
  srt: string,
  courseId: string
  dubId: number
  resource_type:string
  videoSrc:string
}

interface params {
  albumId: string,
  courseId: string,
  index: number,
}

@Builder
export function TabPageBuilder() {
  WorksDetailPage()
}

interface userParams {
  courseId: string,
  uid: string
  showId: string
  tabIndex: number,
  comments: string, // 评论数量
  videoTime?:number,
}

interface like_db_model{
  id : string
  comment_id : string
  is_like: boolean
  uid:string
}

const PAGE_NAME: string = 'WorksDetailPage';

@Component
export struct WorksDetailPage {
  @Consume("pathStack") pathStack: NavPathStack
  //获取窗口对象
  windowClass = AppStorage.get<window.Window>('windowClass') as window.Window;
  difLevelList = ['A', 'A1', 'A2', 'B3', 'B2', 'C1']
  @State courseId: string = ''
  @StorageLink('isLogin') isLogin: boolean = false;
  @State dubId: number = -1;
  @State srt: string = ''
  @State tabsIndex: number = 0
  @State comments: string = '0'
  @State is_support: string = ''
  @State supports: number = 0
  @State userUid: string = ''
  @StorageLink('showId') showId: string = ''
  @State courseTitle: string = ''
  @State album_id: string = ''
  @State courseCreateTime: string = ''
  @State score: string = '0'
  @State score_show: string = '0'
  @State accuracy: string = ''
  @State fluency: string = ''
  @State integrate: string = ''
  @State userShowInfo: WorksDetail = {
    "uid": '',
    "nickname": '',
    "avatar": '',
    "video": '',
    "audio": '',
    "pic": '',
    "course_title": '',
    "user_number": 0,
    "create_time": '',
    "start_time": '',
    "fans": '',
    "shows": '',
    "dv_type": '',
    "talent_status": '',
    "is_talent": '',
    "dav": '',
    "is_vip": '',
    "is_svip": '',
    "is_free_learn": '',
    "is_aisvip": '',
    "community_level": 0,
    "subtitle_num": '',
    "id": '',
    "duration": '',
    "comments": '0',
    "supports": '0',
    "is_support": '',
    "isSupport": false,
  }
  @State userShowList: WorksDetail [] = []
  @State currentIndex: number = 0
  @State avatar: string = ''
  @State avatar_frame:string=''
  @State is_following: string = '0'
  @State is_aisvip: string = '0'
  @State is_svip: string = '0'
  @State grow_level: string = '0'
  @State nickname: string = ''
  @State collect_id:string=''
  @State collect_num:string=''
  // 音频播放器
  audioPlayer: AudioPlayer = new AudioPlayer();
  @StorageLink('breakPoint') breakPoint: string = BreakpointConstants.BREAKPOINT_MD

  @State audioType: boolean = false // 听原音?听配音
  //视频播放状态
  @State @Watch('onVideoPlayChange') videoPlay: boolean = true // 是否播放中

  @State start:number=0

  onVideoPlayChange(){
    if (this.videoPlay) {
      window.getLastWindow(getContext(this)).then((data) =>{
        data.setWindowKeepScreenOn
        (true)})
    }else {
      window.getLastWindow(getContext(this)).then((data) =>{
        data.setWindowKeepScreenOn
        (false)})
    }
  }
  @State detailsId: string = ''
  @State sateVideoState: boolean = false
  @State showController: boolean = true // 是否展示播放器控制器
  @State vol: number = 0 // 音量
  private xcomponentController: XComponentController = new XComponentController();
  @LocalStorageLink('sessionManager') sessionManager: MediaService | null = null
  @State surfaceID: string = '';
  @State isBestShow: number = 0;
  //视频地址视频封面
  @State videoSrc: string = ''
  @State b_id: string = ''
  @State audioSrc: string = ''
  @State videoCover: string = ''
  @State is_needbuy: string = ''
  @State isFull: boolean = false; // 是否开启全屏
  @State PCFull: boolean = false // PC/平板是否全屏

  @State isNeedVip: boolean = false
  @State is_NeedBuy: boolean = false
  @StorageProp('isVip') isVip: string = '';
  @StorageProp('isSVip') isSVip: string = '';
  //分享
  @State share_desc: string = ''
  @StorageProp('resource_type') resource_type:string=''
  @State b_title:string=''
  @State duration:string=''
  @State bg_pic:string=''
  @State album_sort: number = 0
  @State share_url: string = ''
  @State share_title: string = ''
  //视频比例
  @State videoProportion: number = 0
  @State videoHeight: number = 1
  @State videoWidth: number = 1
  @State windowHeight: number = 1
  @State windowWidth: number = 1
  //显示视频总时长
  @State @Watch('setVideoTime') videoTime: number = 0 // 当前播放时长
  @State continueTime:number = 0 //接续时间
  @State endTime: number = 0 // 总时长
  @State detailsVip: string = ''
  @State isNeedBuy: string = ''
  //当前视频进度时间
  @Provide currentTime: number = 0;
  @State audioTime: number = 0
  @State dubbingSentences: DubbingSentence[] = [];
  @State isShowNewWorksList: boolean = false
  @State show_listData: NewWorksListModel[] = []
  @State chinese:string=''
  @State english:string=''
  //播放器
  @State avPlayer: media.AVPlayer | null = null;
  @StorageLink('certificateList')@Watch('certificateChange') certificateList: Certificate = new Certificate()
  @State isShow:boolean=false
  @State albumInfo: AlbumDetails = {
    id: '',
    pic: '',
    album_title: '',
    resource_desc: '',
    sub_title: '',
    course_num: '',
    tag: '',
    category_id: '',
    dif_level: '',
    is_vip: '',
    album_isbuy: '',
    description: '',
    album_vip_price: '',
    is_needbuy: '',
    album_price: '',
    resource_type: '',
    "learn_plan_id": 0,    //计划id 7.91.1
    "learn_plan_course_id": 0,   //计划课程id 7.91.1
    "learn_plan_finish": 0,   //计划是否完成 7.91.1
  }
  private tabsController: TabsController = new TabsController()
  controller: webview.WebviewController = new webview.WebviewController();
  fzJSExportObject: FZJSExportObjectOfVideo = new FZJSExportObjectOfVideo(true)

  // 私密或公开
  @State isHide:boolean=false
  @State collect:boolean=false
  setVideoTime(){
    if (this.routerParam) {
      this.routerParam.videoTime = this.videoTime
    }
  }

  getTime(){
    if (this.resource_type=='5'){
    this.dubbingSentences.forEach((item: DubbingSentence, index)=>{
      if (this.videoTime>=item.start  &&  this.videoTime<=item.end) {
        console.log('当前时长--'+this.videoTime+'当句开始--'+item.start+'当句结束--'+item.end)
        this.chinese=item.captionZh
        this.english=item.caption
      }
    })
  }else{
      if (Number(this.videoTime/1000)>=Number(this.duration)) {
        this.avPlayer?.seek(0)
      }
    }
  }
  openVipPage() {
    if (this.isLogin === false) {
      this.pathStack.pushPathByName('LoginPage', {
        "from": 'WorksDetailPage'
      } as CommonObj)
    } else {
      this.pathStack.pushPathByName('fakeTab', 'listen', () => {
        this.GetUserShowInfo()
      })
    }
  }
  VipPricePage() {
    if (this.isLogin === false) {
      this.pathStack.pushPathByName('LoginPage', {
        "from": 'WorksDetailPage'
      } as CommonObj)
    } else {
      const uid = AppStorage.get<string>('uid');
      this.pathStack.pushPathByName('PayPage', {
        id: this.courseId,
        title:this.albumInfo.album_title,
        price: this.albumInfo.album_price?.toString(),
        vip_price: this.albumInfo.album_vip_price,
        uid: uid
      } as audioInfo)
    }
  }
  pricePage() {
    if (this.isLogin === false) {
      this.pathStack.pushPathByName('LoginPage', {
        "from": 'WorksDetailPage'
      } as CommonObj)
    } else {
      const uid = AppStorage.get<string>('uid');
      this.pathStack.pushPathByName('PayPage', {
        id:  this.albumInfo.id,
        title: this.albumInfo.album_title,
        price: this.albumInfo.album_price?.toString(),
        vip_price: this.albumInfo.album_vip_price?.toString(),
        uid: uid
      } as audioInfo, () => {
        this.GetUserShowInfo()
      })
    }
  }
  private hearingopenNeedVipPop: CustomDialogController = new CustomDialogController({
    builder: openNeedVip({
      openVip: () => {
        this.openVipPage()
      }
    }),
    alignment: DialogAlignment.Center,
    customStyle: true,
    cornerRadius: 10,
    isModal: true
  });
  private hearingVipOrBuyPop: CustomDialogController = new CustomDialogController({
    builder: openVipOrBuy({
      data: this.albumInfo.album_price,
      price: () => {
        this.pricePage()
      },
      openVip: () => {
        this.openVipPage()
      }
    }),
    alignment: DialogAlignment.Center,
    customStyle: true,
    cornerRadius: 10,
    isModal: true
  });
  private hearingVipAndBuyPop: CustomDialogController = new CustomDialogController({
    builder: openVipAndBuy({
      dataPrice: this.albumInfo.album_price,
      dataVipPrice: this.albumInfo.album_vip_price,
      price: () => {
        this.pricePage()
      },
      openVip: () => {
        this.openVipPage()
      }
    }),
    alignment: DialogAlignment.Center,
    customStyle: true,
    cornerRadius: 10,
    isModal: true
  });
  private hearingopenBuyVipPop: CustomDialogController = new CustomDialogController({
    builder: openBuyVip({
      dataPrice: this.isSVip=='1'?this.albumInfo.album_vip_price:this.albumInfo.album_price,
      price: () => {
        this.VipPricePage()
      },
      // openVip:()=>{
      //   this.openVipPage()
      // }
    }),
    alignment: DialogAlignment.Center,
    customStyle: true,
    cornerRadius: 10,
    isModal: true
  });
  certificateStudyDialog: CustomDialogController | null = new CustomDialogController({
    builder: CertificateStudyDialog({
      current_plan_certificateList: this.certificateList
    }),
    maskColor: 'rgba(0, 0, 0, 0.70)',
    alignment: DialogAlignment.Center, // 弹窗在竖直方向上的对齐方式。
    customStyle: true, // 弹窗容器样式是否自定义。
  })
  certificateChange(){
    if (this.isShow){
      if (this.certificateList!=undefined ) {
        if (this.certificateList.is_look =='0'){
          if (this.certificateStudyDialog!=null) {
            this.certificateStudyDialog.open()
            SoundPlayer.getSoundPlayer().play('winning_bg_all.wav')
          }
        }

      }
    }
  }
  // avplayer状态机
  private setAVPlayerCallback(avPlayer: media.AVPlayer) {
    // startRenderFrame首帧渲染回调函数
    avPlayer.on('startRenderFrame', () => {
      console.info(`AVPlayer start render frame`);
    })
    // 音量
    avPlayer.on('volumeChange', (vol: number) => {
      this.vol = vol
    })
    // seek操作结果回调函数
    avPlayer.on('seekDone', async (seekDoneTime: number) => {
      console.info('zzz=== avPlayer seek操作', ` seek time is ${seekDoneTime}`);
      let ap = await this.audioPlayer.getPlayer();
      console.info('zzz=== avPlayer seek操作', ` 当前ap状态:${ap?.state}`);
      if (ap?.state == 'paused' || ap?.state == 'playing' || ap?.state == 'prepared') {
        ap?.seek(seekDoneTime);
      }
      // let data:emitter.EventData={
      //   data:{
      //     seekDoneTime
      //   }
      // }
      // emitter.emit('VedioseekDone',data)
    })
    // error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程
    avPlayer.on('error', (err: BusinessError) => {
      console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
      avPlayer.reset(); // 调用reset重置资源,触发idle状态
      emitter.emit('VedioError')
    })
    // 时间更新 监听资源播放当前时间,单位为毫秒(ms),用于刷新进度条当前位置,默认间隔100ms时间上报,因用户操作(seek)产生的时间变化会立刻上报。
    avPlayer.on('timeUpdate', async (time: number) => {
      this.videoTime = time
      this.getTime()
      let ap = await this.audioPlayer.getPlayer();
      if (ap) {
        let difference = (ap.currentTime > (time + 300) || ap.currentTime < (time - 300))
        if (difference && (ap?.state == 'paused' || ap?.state == 'playing' || ap?.state == 'prepared')) {
          console.log('zzz=== avPlayer时间校准', `当前视频时间:${time} ;当前音频时间 ${ap.currentTime}`)
          ap.seek(time);
        }
      }
    })
    // 状态机变化回调函数
    avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
      console.log('zzz=== avPlayer状态变化', `当前状态${state}`)
      switch (state) {
        case 'idle': // 成功调用reset接口后触发该状态机上报
          console.log('AVPlayer状态机 state idle called.');
          let ap = await this.audioPlayer.getPlayer()
          ap?.reset()
          break;
        case 'initialized': // avplayer 设置播放源后触发该状态上报
          console.log('AVPlayer状态机 state initialized called.');
          avPlayer.url
          if (this.resource_type!='5') {
            avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置
          }
          //监听
          emitter.emit('VideoInitialized')
          avPlayer.prepare();
          break;
        case 'prepared': // prepare调用成功后上报该状态机已准备状态,在initialized状态调用prepare()方法,AVPlayer会进入prepared状态,此时播放引擎的资源已准备就绪。
          console.log('AVPlayer状态机 state prepared called.');
          // this.isLoading = false;
          this.endTime = avPlayer.duration
          avPlayer.videoScaleType = 1
          avPlayer.setVolume(0)
          // this.VideoSize(this.windowHeight, this.windowWidth)
          this.listenVieoVoice()
          if (this.continueTime) {
            avPlayer.seek(this.continueTime)
            this.continueTime = 0
          }
          this.doPlay()
          break;
        case 'playing': // play成功调用后触发该状态机上报
          console.log('AVPlayer状态机 state playing called.');
          // avPlayer.setVolume(0)
          // this.videoPlay = true
          this.videoPlay = true
          //监听
          emitter.emit('VideoPlaying')
          break;
        case 'paused': // pause成功调用后触发该状态机上报
          console.log('AVPlayer状态机 state paused called.');
          this.videoPlay = false
          //监听
          emitter.emit('VideoPaused')
          break;
        case 'completed': // 播放结束后触发该状态机上报
          console.log('AVPlayer状态机 state completed called.');
          // avPlayer.stop(); //调用播放结束接口
          // this.videoComplete()
          this.videoPlay = false
          // this.doPlay()
          //监听
          emitter.emit('VideoCompleted')
          break;
        case 'stopped': // stop接口成功调用后触发该状态机上报
          console.log('AVPlayer状态机 state stopped called.');
          avPlayer.reset(); // 调用reset接口初始化avplayer状态
          //监听
          emitter.emit('VideoStopped')
          break;
        case 'released':
          console.log('AVPlayer状态机 state released called.');
          break;
        default:
          console.info('AVPlayer state unknown called.');
          break;
      }
    })
    //视频尺寸变化
    avPlayer.on('videoSizeChange', (width: number, height: number) => {
      console.log('myTag', '获取视频比例')
      this.videoProportion = (height / width)
      // this.VideoSize(this.windowHeight, this.windowWidth)
    })
  }


  private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  //续接参数
  @StorageLink('ContinueRouterParams') continueRouterParams:CommonObj = {}

  //保存参数
  setContinueStateParams() {
    if (!this.continueRouterParams) {
      this.continueRouterParams = {}
    }
    this.continueRouterParams.uid = AppStorage.get('uid')
    this.continueRouterParams.name = PAGE_NAME
    let courseInfo: userParams[]
    if (this.courseInfo.length == 0) {
      this.courseInfo = this.pathStack.getParamByName(PAGE_NAME) as userParams[]
    }
    courseInfo = this.courseInfo
    this.routerParam = courseInfo[courseInfo.length-1]
    this.continueRouterParams.params = courseInfo
  }

  //开启应用接续
  openContinueState(){
    this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
      console.info('setMissionContinueState ACTIVE result: ', JSON.stringify(result));
    });
  }
  closeContinueState(){
    this.context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) => {
      console.info(`setMissionContinueState: ${JSON.stringify(result)}`);
    });
  }

  @State courseInfo:userParams[] = []
  @State routerParam:userParams|undefined = undefined

  async aboutToAppear() {
    // this.windowClass.setWindowLayoutFullScreen(false);
    // this.windowClass.setSpecificSystemBarEnabled('status', true);
    // this.windowClass.setSpecificSystemBarEnabled('navigationIndicator', false);
    let courseInfo: userParams [] = this.pathStack.getParamByName('WorksDetailPage') as userParams[]
    this.routerParam = courseInfo[courseInfo.length-1]
    if (this.routerParam.videoTime) {
      this.continueTime = this.routerParam.videoTime
    }
    console.log('courseInfo', JSON.stringify(courseInfo))
    this.courseId = courseInfo[courseInfo.length - 1].courseId
    this.userUid = courseInfo[courseInfo.length - 1].uid
    this.showId = courseInfo[courseInfo.length - 1].showId
    this.tabsIndex = courseInfo[courseInfo.length - 1].tabIndex || 0
    this.comments = courseInfo[courseInfo.length - 1].comments
    // this.courseId = '492004'
    // this.userUid = '70847240'
    await this.bindAudio()
    this.avPlayer = await media.createAVPlayer();
    this.setAVPlayerCallback(this.avPlayer);
    this.show_list()
    await this.GetUserShowInfo()
    if(Number(this.courseId)>0) {
      await this.GetCourseInfo()
    }
    await this.detailsSupport()
    this.windowClass.on('windowSizeChange', (size) => {
      let viewWidth = px2vp(size.width);
      let viewHeight = px2vp(size.height);
      // this.videoWidth = viewWidth
      // this.videoHeight = viewHeight

      if (viewWidth > viewHeight) {
        // ...
      } else {
        // ...
      }
      // ...
    });
    // this.setOrientation(13)
    // 开启屏幕常亮
    // let isFocusable: boolean = true;
    // try {
    //   let promise = this.windowClass.setWindowFocusable(isFocusable);
    //   promise.then(() => {
    //     console.info('Succeeded in setting the window to be focusable.');
    //   }).catch((err: BusinessError) => {
    //     console.error(`Failed to set the window to be focusable. Cause code: ${err.code}, message: ${err.message}`);
    //   });
    // } catch (exception) {
    //   console.error(`Failed to set the window to be focusable. Cause code: ${exception.code}, message: ${exception.message}`);
    // }
    if (this.showController == true) {
      // 三秒后隐藏控件
      setTimeout(() => {
        this.changeController()
      }, 2000)
    }

    this.tabsController.preloadItems([0,1])

    try {
      if (!this.continueRouterParams) {
        this.continueRouterParams = {}
      }
      // 开启应用接续
      this.continueRouterParams.name = PAGE_NAME
      this.continueRouterParams.params = this.pathStack.getParamByName(PAGE_NAME)
      this.setContinueStateParams()
      this.openContinueState()
    }catch (e) {
      // let a = e
    }

  }

  async aboutToDisappear() {
    if (this.breakPoint!='xl'){
      this.setOrientation(window.Orientation.PORTRAIT) // 回复竖屏
    }
    // this.windowClass.off('windowSizeChange');
    this.avPlayer?.release()
    let ap = await this.audioPlayer.getPlayer()
    ap?.release()
    // 关闭屏幕常亮
    // let isFocusable: boolean = false;
    // try {
    //   let promise = this.windowClass.setWindowFocusable(isFocusable);
    //   promise.then(() => {
    //     console.info('Succeeded in setting the window to be focusable.');
    //   }).catch((err: BusinessError) => {
    //     console.error(`Failed to set the window to be focusable. Cause code: ${err.code}, message: ${err.message}`);
    //   });
    // } catch (exception) {
    //   console.error(`Failed to set the window to be focusable. Cause code: ${exception.code}, message: ${exception.message}`);
    // }
    // this.windowClass.setWindowLayoutFullScreen(false);
    // this.windowClass.setSpecificSystemBarEnabled('status', true);
    // this.windowClass.setSpecificSystemBarEnabled('navigationIndicator', false);
    this.onWindowSizeChange()
  }

  //
  onWindowSizeChange(){
    this.windowClass.on('windowSizeChange', (size) => {

      let viewWidth = px2vp(size.width);
      let viewHeight = px2vp(size.height);
      this.videoWidth = viewWidth
      // this.videoHeight = viewHeight

      if (viewWidth > viewHeight) {
        console.log('横屏viewHeight', viewHeight)
        // this.videoHeight = viewHeight - 80
      } else {
        console.log('竖屏viewHeight', viewHeight)
      }

    });
  }

  async onPageShow() {
    this.sessionManager?.release()
    this.sessionManager = null
    this.setContinueStateParams()
  }

  async onPageHide() {
    console.log('页面隐藏')
    // this.avPlayer?.release()
    this.doPause()
    if (this.breakPoint!='xl'){
      this.setOrientation(window.Orientation.PORTRAIT) // 回复竖屏
    }
    // this.windowClass.off('windowSizeChange');
  }
  //返回字幕数组
  _reqSrtText(srt: string) {
    return new Promise<DubbingSentence[]>((resolve: Function, reject: Function) => {
      CommonApi.GetSrt(srt)
        .then((result: string) => {
          const ret = result
          console.log('zzz=== 获取字幕完整字段', ret)
          let dubbing = ret.split(/\n\s*\n/).filter(item => item != "").map((item, index) => {
            console.log('zzz=== 获取字幕单句字段', item)
            let textItem = item.split(/\n/)
            console.info('get srt result:', textItem);
            let timeStr = textItem[1].replace(/\s/, "").split("-->")
            let savedAddress = `${index}`
            // let savedAddress = `${this.filename()}${this.courseId}${index}`
            if (textItem.length==4) {
              return new DubbingSentence(index, textItem[2], textItem[3], getSecond(timeStr[0]), getSecond(timeStr[1]),
                savedAddress)
            }else{
              return new DubbingSentence(index, '', textItem[2], getSecond(timeStr[0]), getSecond(timeStr[1]),
                savedAddress)
            }
          })
          resolve(dubbing)
        })
    })
  }
  // 是否开启临时横屏事件,13-竖屏;14-横屏
  setOrientation(orientation: number) {
    window.getLastWindow(getContext(this)).then((win) => {
      win.setPreferredOrientation(orientation).then((data) => {
        console.log('setWindowOrientation: ' + orientation + ' Succeeded. Data: ' + JSON.stringify(data));
      }).catch((err: string) => {
        console.log('setWindowOrientation: Failed. Cause: ' + JSON.stringify(err));
      });
    }).catch((err: string) => {
      console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err));
    });
  }

  async GetUserShowInfo() {
    await WorkApi.getUserShowInfo(this.showId).then(async (res) => {
      this.isHide=res.is_hide=='1'?true:false
      this.is_needbuy = res.is_needbuy
      this.videoSrc = res.course_video
      this.duration=res.duration
      this.resource_type='1'
      this.share_desc = res.share_desc
      this.album_sort = Number(res.album_sort)
      this.share_title = res.share_title
      this.detailsVip = res.is_vip
      this.isNeedBuy = res.is_needbuy
      this.share_url = res.share_url
      console.log('首页点击work---------' + this.isNeedBuy + "-----" + this.detailsVip)
      this.detailsId = res.id
      this.audioSrc = res.audio
      this.videoCover = res.pic
      this.srt = res.subtitle_en
      this.courseTitle = res.course_title
      this.album_id = res.album_id
      this.courseCreateTime = res.create_time
      this.courseId = res.course_id
      this.nickname = res.nickname
      this.avatar = res.avatar
      this.avatar_frame=res.avatar_frame
      this.isBestShow = res.is_best_show
      this.comments = res.comments
      this.is_following = res.is_following
      this.supports = res.supports
      this.userUid = res.uid
      this.is_aisvip = res.is_aisvip
      this.is_svip = res.is_svip
      this.grow_level = res.grow_level
      this.collect_id=res.collect_id
      this.collect_num=res.collects
      this.collect=this.collect_id?true:false
      this.score = res.score
      this.score_show = res.score_show
      this.accuracy = res.accuracy
      this.fluency = res.fluency
      this.integrate = res.integrate
      if (res.resource_type=='2'){
        this.resource_type=res.resource_type
        this.videoSrc = res.embed_video_url
        this.audioSrc = res.audio
        this.b_id = res.b_id
        this.b_title=res.course_title
      }else if (res.resource_type=='5'){
        //文本
        this.resource_type=res.resource_type
        this.duration=res.duration
        this.bg_pic=res.bg_pic   //背景图
        this.videoSrc=res.original_audio  //原始音频
        // this.srt=res.subtitle_en  //字幕
        this.dubbingSentences= await this._reqSrtText(res.subtitle_en)
      }
      setTimeout(()=>{
        if (this.avPlayer) {
          this.avPlayer.url = this.videoSrc
        }
        this.audioPlayer.setUrl(this.audioSrc)
        this.audioPlayer.avPlayerLive()

      },300)
      this.getDubid()
      if (res.is_needbuy=='1') {
        //如果需要购买,查询专辑详情
        this.albumDetails(res.album_id)
      }
    }).catch((msg: string) => {
      ToastUtil.showToast(msg);
    })
  }
  albumDetails(albumId:string){
    AlbumApi.getAlbumDetails(albumId, 0).then((res) => {
      console.log('albumList', res)
      this.albumInfo = res
      let listenByBuy = this.albumInfo.album_isbuy == '1';
      let listenByVip = this.albumInfo.is_vip == '2' && this.isSVip == '1';
      this.is_NeedBuy = Number(this.albumInfo.album_price??0) != 0 && !(listenByBuy || listenByVip);
      this.isNeedVip = this.albumInfo.is_vip == '2' && !(this.isSVip == '1' || listenByBuy);
    }).catch((msg: string) => {
      ToastUtil.showToast(msg);
    })
  }
  async GetCourseByIndex(index: number) {
    let data = this.userShowList[index]
    this.showId = data.id
    // await this.bindAudio()
    await this.GetUserShowInfo()
    console.log('showid---------'+this.showId+'---------'+index)
  }

  async ToPlayShow(data: WorksDetail) {
    this.videoSrc = data.video
    if (this.avPlayer) {
      this.avPlayer.url = this.videoSrc
    }
    this.audioSrc = data.audio
    this.audioPlayer.setUrl(this.audioSrc)
    this.audioPlayer.avPlayerLive()
    this.videoCover = data.pic
    this.courseTitle = data.course_title
    this.courseCreateTime = data.create_time
    this.nickname = data.nickname
    this.avatar = data.avatar
    this.is_aisvip = data.is_aisvip
    this.is_svip = data.is_svip
  }

  async detailsSupport() {
    WorkApi.detailsSupport(this.showId).then((res) => {
      this.is_support = res.is_support
      console.log('是否点赞--------' + this.is_support)
    })
  }

  async GetCourseInfo() {
    WorkApi.getUserShowList(this.userUid, this.courseId,this.start,10).then((res) => {
      if (this.userShowList.length==0) {
        this.userShowList = res
      }else {
        this.userShowList=[...this.userShowList,...res]
      }
    }).catch((msg: string) => {
      ToastUtil.showToast(msg);
    })
  }

  //控制滑动条拖动与当前时间一致并开始播放
  async sliderOnchange(value: number, mode: SliderChangeMode) {
    // this.currentTime = Number.parseInt(value.toString());
    // this.controller.setCurrentTime(Number.parseInt(value.toString()), SeekMode.Accurate);
    //
    // let ap = await this.audioPlayer.getPlayer();
    // if (ap?.state == 'paused' || ap?.state == 'playing' || ap?.state =='prepared') {
    //   ap?.seek(value);
    // }
  }

  async doPlay() {
    let ap = await this.audioPlayer.getPlayer()
    let mp = this.avPlayer
    console.log('zzz=== doPlay方法', `mp状态:${mp?.state};ap状态:${ap?.state}`)
    if (ap?.state == mp?.state && (mp?.state == "prepared" || mp?.state == "paused" || mp?.state == "completed")) {
      mp.play()
      ap?.play()
    } else {
      // ToastUtil.showToast('视频播放出现了点问题')
    }
  }

  async doPause() {
    let ap = await this.audioPlayer.getPlayer()
    let mp = this.avPlayer
    console.log('zzz=== doPause方法', `mp状态:${mp?.state};ap状态:${ap?.state}`)
    if (ap?.state == 'playing') {
      ap?.pause()
    }
    if (mp?.state == 'playing') {
      mp.pause()
    }
  }

  // 播放器控件
  changeController() {
    animateTo({ duration: 600 }, () => {
      this.showController = !this.showController
    })
  }

  //
  async listenVieoVoice() {
    let mp = this.avPlayer
    let ap = await this.audioPlayer.getPlayer()
    if (ap?.state == mp?.state &&
      (mp?.state == "prepared" || mp?.state == "playing" || mp?.state == "paused" || mp?.state == "completed")) {
      this.audioType = !this.audioType
      mp?.setVolume(this.audioType ? 0 : 1)
      ap?.setVolume(!this.audioType ? 0 : 1)
      console.log('设置音频音量')
    }
  }

  //音视频频绑定
  async bindAudio() {
    let ap = await this.audioPlayer.getPlayer()
    if (ap) {
      ap.on('volumeChange', (vol: number) => { //配音播放监听音量
        this.vol = vol
      })
    }
    emitter.on('AudioPrepared', () => {
      if (this.isShow) {
        this.listenVieoVoice()
        this.doPlay()
      }
    })
    emitter.on('VideoPaused', () => { //暂停
      ap?.pause()
    })
    emitter.on('completed', () => { //完成
      // ap?.stop()
    })
    emitter.on('VedioError', () => { //完成
      ap?.reset()
    })
    emitter.on('idle', () => { // video调用reset后
      console.log('视频初始化')
      ap?.reset()
    })


  }

  //视频比例适应
  VideoSize(height: number, width: number) {
    console.log('视频比例调整-宽', width, '视频比例调整-高',height)
    console.log('计算高度', width * 9/16)
    let countHeight = width * 9/16

    if (this.isFull) {
      this.videoWidth = width - 150
    } else {
      this.videoWidth = width
    }
    if(this.PCFull) {
      setTimeout(()=>{
        this.videoHeight = countHeight
      },100)
    } else {
      let normalHeight = this.videoWidth * 9/16
      this.videoHeight = normalHeight
    }
  }

  // 横竖屏切换
  horVerSwitch() {
    
    // let orientation = window.Orientation.AUTO_ROTATION;
    // this.windowClass.setPreferredOrientation(orientation)

     // this.windowClass.setWindowLayoutFullScreen(true);
    // this.windowClass.setSpecificSystemBarEnabled('status', false);
    // this.windowClass.setSpecificSystemBarEnabled('navigationIndicator', false);
    let context = getContext(this) as common.UIAbilityContext;
    // 使用getLastWindow获取当前窗口
    window.getLastWindow(context).then((lastWindow) => {
      // 使用setPreferredOrientation实现横竖屏切换
      lastWindow.setPreferredOrientation(this.isFull ? window.Orientation.PORTRAIT : window.Orientation.LANDSCAPE)
      this.isFull = !this.isFull
    })
  }

  getDubid() {

    emitter.on('queryDubIdSuccess', (data) => {
      let id: number = (data.data)?.['id'];
      this.dubId = id
    })
    emitter.emit('queryDubIdByCourseId', { data: { courseId: Number(this.courseId) } })
  }

  show_list(){
    WorkApi.show_list(this.courseId, 0, 5).then((res: NewWorksListModel[]) => {
      this.show_listData = res;
    })
  }
  //跳转B站app
  openBilibiliApp(){
    const link = `https://www.bilibili.com/video/${this.b_id}`; // 替换为实际的B站视频链接
    let context = getContext(this) as common.UIAbilityContext;
    let openLinkOptions: OpenLinkOptions = {
      appLinkingOnly: true,
    };
    try {
      context.openLink(link, openLinkOptions, (err, result) => {
        console.log(err+''+result)
      }
      ).then(() => {
        console.log('跳转成功')
      }).catch((err: BusinessError) => {
        console.log('err')
        ToastUtil.showToast('未安装哔哩哔哩,请安装后重试');
      });
    }
    catch (e) {
    }
  }
  // 注入JavaScript代码
  private injectPlayScript() {
    try {
      const jsCode = "(function() { " +
        "var videos = document.getElementsByTagName('audio');" +
        " for(var i=0;i<videos.length;i++){videos[i].play();} return videos})()";
      this.controller.runJavaScript(jsCode).then((result) => {
        console.log('result: ' + result);
        const basePlayedJsInjection =
          "window.player.on("%s",function(){window.player.playerPromise.then(function(player){" +
            "window.fZJSExportObject.jsCallback(JSON.stringify({action: 51,content: JSON.stringify({isPlaying: %s})}))})})"
        const endedJs = format(basePlayedJsInjection, "video_media_ended", false);
        const pauseJs = format(basePlayedJsInjection, "video_media_pause", false);
        const playJs = format(basePlayedJsInjection, "video_media_play", true);
        this.controller.runJavaScript(endedJs)
        this.controller.runJavaScript(pauseJs)
        this.controller.runJavaScript(playJs)
        this.controller.runJavaScript("window.player.play()").then(res => {
          setTimeout(()=>{
            this.controller.runJavaScript("window.player.seek(0.1)")
          },500)
        })
          .catch((error: BusinessError) => {
            console.error("error: " + error);
          })
      })
        .catch((error: BusinessError) => {
          console.error("error: " + error);
        })

    } catch (error) {
      console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
    }
  }
  openDubbing(){
    console.log('去配音页面')
    console.log('去配音页面  ' + this.courseId)
    if (this.isLogin) {
      // if (this.is_NeedBuy){
      // if (this.isNeedVip == true && Number(this.album_price) != 0) {
      if (this.isNeedVip && this.is_NeedBuy) {
        this.hearingVipOrBuyPop.open()
      } else if (this.isNeedVip  && !this.is_NeedBuy) {
        this.hearingopenNeedVipPop.open()
      } else if (this.is_NeedBuy == true && this.isSVip != '1') {
        this.hearingVipAndBuyPop.open()
      } else if (this.is_NeedBuy == true && this.isSVip == '1') {
        this.hearingopenBuyVipPop.open()
        // }
      } else{
        this.avPlayer?.pause()
        this.pathStack.pushPathByName('QPYDubbing', {courseId: this.courseId, srt: this.srt,dubId:this.dubId,resource_type:this.resource_type,videoSrc:this.videoSrc} as dubbingParams,
          (data) => {
            if (data.info.param) {
              let param = data.info.param as dubbingParams
              this.dubId = param.dubId
            }
          })
      }
    } else {
      this.pathStack.replacePathByName('LoginPage', {
        "from": 'WorksDetailPage'
      } as CommonObj)
    }
  }

  doBack(){
    this.pathStack.pop({})
    this.closeContinueState()
  }

  build() {
    NavDestination() {
      Flex({justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center,wrap: FlexWrap.Wrap}) {
          Column() {
            // 顶部视频播放模块
            Stack({ alignContent: Alignment.Top }) {
              if (this.resource_type=='2'){
                Column(){
                  Row(){
                    Stack(){
                      Text(this.b_title)
                        .width('100%')
                        .fontSize(replaceLpx2Vp(36))
                        .fontColor('#333333')
                        .textAlign(TextAlign.Center)
                        .fontWeight(500)
                      Row(){
                        Image($r('app.media.ic_close')).width(replaceLpx2Vp(45)).height(replaceLpx2Vp(45)).margin({left:replaceLpx2Vp(34)})
                          .onClick(()=>{
                            // this.pathStack.pop({})
                            this.doBack()
                          })
                      }.width('100%')
                    }.width('100%')
                  }.height(replaceLpx2Vp(88)).width('100%').padding({right:replaceLpx2Vp(35)})
                  Row(){
                    Image($r('app.media.ic_bilibili')).height(replaceLpx2Vp(58)).margin({left:replaceLpx2Vp(34),top:replaceLpx2Vp(13),bottom:replaceLpx2Vp(16)})
                    Blank().layoutWeight(1)
                    // Text('去bilibili看原视频>').fontSize(replaceLpx2Vp(28)).fontColor('#FA7299').margin({right:replaceLpx2Vp(24)})
                    //   .onClick(()=>{
                    //     this.openBilibiliApp()
                    //   })
                  }.height(replaceLpx2Vp(88)).width('100%')
                  Web({src:this.resource_type=='2'?this.videoSrc:'',controller: this.controller })
                    .onControllerAttached(() => {
                      if (this.fzJSExportObject) {
                        this.controller.registerJavaScriptProxy(this.fzJSExportObject.getInstance(this.pathStack,
                          this.controller), "fZJSExportObject", ["jsCallback"])
                      }
                    })
                    .onPageEnd(() => {
                      // 页面加载完成后,注入JavaScript代码
                      this.injectPlayScript();
                    })
                    .width('100%').zIndex(11).height(this.breakPoint===BreakpointConstants.BREAKPOINT_XL?replaceLpx2Vp(622):replaceLpx2Vp(422))
                }.backgroundColor('#ffffff')
                .width('100%').height(replaceLpx2Vp(510))
              }else if (this.resource_type=='5') {
                Stack(){
                  WorkTextDubbing({avPlayer: this.avPlayer, windowHeight:replaceLpx2Vp(422).toString(),bg_pic:this.bg_pic,
                    subtitle_en:this.srt, endTime:Number(this.duration),chinese:this.chinese,english:this.english,videoTime:this.videoTime})
                  Column(){
                    Image($r('app.media.ic_arrow_left_02')).width(replaceLpx2Vp(45)).height(replaceLpx2Vp(45)).margin({top:replaceLpx2Vp(24),left:replaceLpx2Vp(24)})
                      .onClick(()=>{
                        // this.pathStack.pop({})
                        this.doBack()
                      })
                    Blank().layoutWeight(1)
                  }.width('100%').height(replaceLpx2Vp(422)).alignItems(HorizontalAlign.Start)
                }.width('100%').height(replaceLpx2Vp(422))
              }else {
                // 视频播放器
                XComponent({ type: XComponentType.SURFACE, controller: this.xcomponentController })
                  .onLoad(async e => {
                    this.surfaceID = this.xcomponentController.getXComponentSurfaceId()
                  })
                  .height(this.isFull ? '100%' : this.videoHeight)
                  .width(this.videoWidth)
                  .onClick(() => {
                    animateTo({ duration: 600 }, () => {
                      if (this.showController == true) {
                        return
                      }
                      this.showController = !this.showController
                      // 三秒后隐藏控件
                      setTimeout(() => {
                        this.changeController()
                      }, 2000)
                    })
                  })

                // 播放器自定义控件
                if (this.showController) {
                  Row() {
                    Image($r('app.media.ic_arrow_left_02'))
                      .width(this.isFull ? '22lpx' : this.breakPoint === BreakpointConstants.BREAKPOINT_MD ? '44lpx' : replaceLpx2Vp(44))
                      .onClick(() => {
                        if(this.breakPoint==BreakpointConstants.BREAKPOINT_XL) {
                          if(this.PCFull) {
                            animateTo({ duration: 500 }, () => {
                              this.PCFull = !this.PCFull
                            })
                          } else {
                            // this.pathStack.pop({})
                            this.doBack()
                          }
                        } else {
                          if (this.isFull) {
                            this.isFull = !this.isFull
                            if (this.breakPoint!='xl'){
                              this.setOrientation(window.Orientation.PORTRAIT) // 回复竖屏
                            }
                          } else {
                            // this.pathStack.pop({})
                            this.doBack()
                          }
                        }
                    })
                  }.padding({ left: replaceLpx2Vp(25), right: replaceLpx2Vp(25), top: replaceLpx2Vp(25) }).width('100%')
                  .transition({ type: TransitionType.Delete, opacity: 0 })

                  Row() {
                    if (this.videoPlay) {
                      Image($r('app.media.ic_play_on'))
                        .imageWith(this.isFull,this.breakPoint)
                        // .width(this.isFull ? '18lpx': this.breakPoint === BreakpointConstants.BREAKPOINT_MD ? '36lpx': replaceLpx2Vp(36)) //replaceLpx2Vp(36)
                        .margin({ right: replaceLpx2Vp(24) }).onClick(() => {
                        this.videoPlay = false
                        this.doPause()
                      })
                    } else {
                      Image($r('app.media.ic_play_off'))
                        .imageWith(this.isFull,this.breakPoint)
                        //.width(replaceLpx2Vp(36))
                        .margin({ right: replaceLpx2Vp(24) }).onClick(() => {
                        this.videoPlay = true
                        this.doPlay()
                      })
                    }
                    Text(commonTs.GetTimeString(this.videoTime)).fontColor(Color.White)
                      .fontSize(this.isFull ? '16lpx' :
                        this.breakPoint === BreakpointConstants.BREAKPOINT_MD ? '22lpx' : replaceLpx2Vp(22))
                    Stack() {
                      Slider({
                        value: this.videoTime,
                        min: 0,
                        max: this.endTime,
                        step: 0.01,
                      })
                        .width(this.videoWidth-135)
                        .videoSlider()//控制播放进度
                        .onChange((value: number, mode: SliderChangeMode) => {
                          if (mode == 0) {
                            console.log('zzz=== 进度条点击事件')
                            this.sateVideoState = this.videoPlay
                            this.doPause()
                          }
                          if (mode == 1) {
                            this.avPlayer?.seek(value, media.SeekMode.SEEK_CLOSEST)
                          }
                          if (mode == 2) {
                            console.log('zzz=== 进度条松开事件')
                            this.avPlayer?.seek(value, media.SeekMode.SEEK_CLOSEST)
                            if (this.sateVideoState) {
                              this.doPlay()
                            }
                          }
                        })
                    }
                    Text(commonTs.GetTimeString(this.endTime)).fontColor(Color.White)
                      .fontSize(this.isFull ? '16lpx' :
                        this.breakPoint === BreakpointConstants.BREAKPOINT_MD ? '22lpx' : replaceLpx2Vp(22))
                    Image($r('app.media.ic_full_screen'))
                      .imageWith(this.isFull,this.breakPoint)
                      // .width(replaceLpx2Vp(36))
                      .margin({ left: replaceLpx2Vp(24) })
                      // .visibility(this.breakPoint == BreakpointConstants.BREAKPOINT_MD?Visibility.Visible:Visibility.None)
                      .onClick(() => {
                        console.log('全屏事件')
                        if (this.avPlayer) {
                          if(this.breakPoint == BreakpointConstants.BREAKPOINT_MD) {
                            this.isFull = !this.isFull
                            if (this.isFull) {
                              this.setOrientation(window.Orientation.LANDSCAPE)
                            } else {
                              if (this.breakPoint!='xl'){
                                this.setOrientation(window.Orientation.PORTRAIT) // 回复竖屏
                              }
                            }
                          } else {
                            animateTo({ duration: 500 }, () => {
                              this.PCFull = !this.PCFull
                            })
                          }
                        }
                      })
                  }
                  .width('100%')
                  .height(this.isFull ? '34lpx' :
                    this.breakPoint === BreakpointConstants.BREAKPOINT_MD ? '68lpx' : replaceLpx2Vp(68))
                  .position({ bottom: 0, left: 0 })
                  .backgroundColor('rgba(23,23,26,0.8)')
                  .alignItems(VerticalAlign.Center)
                  .padding({ left: replaceLpx2Vp(24), right: replaceLpx2Vp(24) })
                  .justifyContent(FlexAlign.SpaceBetween)
                  .transition({ type: TransitionType.Insert, opacity: 0 })
                  .transition({ type: TransitionType.Delete, opacity: 0 })
                }
              }
            }
            .constraintSize(this.isFull ? {} : {
              minHeight: this.windowWidth / 4
            })
            .width('100%')
            .zIndex(1)

            .backgroundColor('#333333')
            .height(this.isFull ? '100%' :
              this.breakPoint === BreakpointConstants.BREAKPOINT_XL ? this.videoHeight : this.videoHeight)
            .onAreaChange((oldValue: Area, newValue: Area) => {
              if (this.isFull == false) {
                this.VideoSize(Number(newValue.height), Number(newValue.width))
              }else {
                if (!this.PCFull) {
                  this.VideoSize(Number(newValue.height), Number(newValue.width))
                }
              }
            })
            .clip(true)
        }.width(this.breakPoint == BreakpointConstants.BREAKPOINT_MD ? '100%' : this.breakPoint == BreakpointConstants.BREAKPOINT_XL ? this.PCFull? '100%' : '60%' : this.PCFull? '100%' : '49%').zIndex(900)
          .height(this.breakPoint == BreakpointConstants.BREAKPOINT_MD ? '' : '100%')

      }
      .width('100%')
      .height('100%')
      .backgroundColor(Color.White)
    }
    .hideTitleBar(true)
    .onKeyEvent((e)=>{
      if (e.keyText=='KEYCODE_ESCAPE') {
        this.avPlayer?.release()
        // this.pathStack.pop({})
        this.doBack()
      }
    })
    .onWillShow(() => {
      this.onPageShow()
      this.isShow=true
    })
    .onHidden(() => {
      this.isShow=false
      this.onPageHide()
    })
    .onReady((context: NavDestinationContext) => {

    })
    .onBackPressed(() => {
      this.closeContinueState()
      // this.pathStack.pop({})
      this.doBack()
      return true
    })
  }


  Support() {
    if (this.is_support == '0') {
      WorkApi.getSupport(this.showId, this.detailsId, '1').then(() => {
        this.is_support = '1'
        this.supports ++
      })
    } else {
      WorkApi.getSupport(this.showId, this.detailsId, '0').then(() => {
        this.is_support = '0'
        this.supports --
      })
    }
  }
}


@Component
struct IconAndCount{
  @Prop count: string | number = ''
  @Prop icon: string | Resource = ''
  build() {
    Row() {
      Image(this.icon)
        .width(replaceLpx2Vp(24))
        .height(replaceLpx2Vp(24))
        .margin({ right: replaceLpx2Vp(5) })
      Text(this.count + '')
        .fontSize(11)
        .fontColor('#ffaeaeae')
    }
  }
}
import { AVPlayerDemo, MediaType } from './AVPlayer';

export class AudioPlayer extends AVPlayerDemo {
  constructor() {
    super(MediaType.Audio);
  }
}
import { media } from '@kit.MediaKit';
import { BusinessError } from '@kit.BasicServicesKit';
import emitter from '@ohos.events.emitter';
import { common } from '@kit.AbilityKit';
import { fileIo as fs } from '@kit.CoreFileKit';

export enum MediaType {
  Video,
  Audio
}

export class AVPlayerDemo {
  private surfaceID: string | null = null; // surfaceID用于播放画面显示,具体的值需要通过Xcomponent接口获取,相关文档链接见上面Xcomponent创建方法
  private fileSize: number = -1;
  private fd: number = 0;
  private url: string = '';
  private type: MediaType = MediaType.Video
  private player: media.AVPlayer | null = null;
  private promiseA: Promise<void> | null = null;
  private isSeek: boolean = true; // 用于区分模式是否支持seek操作
  private context = getContext(this) as common.UIAbilityContext;
  private filesDir = this.context.filesDir;
  private file = fs.openSync(this.filesDir + '/02.m4a', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

  constructor(type: MediaType) {
    this.type = type ?? this.type;
    this.initPlayer();
  }

  async initPlayer() {
    if (!this.promiseA) {
      this.promiseA = new Promise(async (resolve, reject) => {
        this.player = await media.createAVPlayer();
        resolve()
      })
    }
    return this.promiseA;
  }

  async reset() {
    let avPlayer: media.AVPlayer = (await this.getPlayer())!;
    avPlayer.reset();
  }

  async getPlayer() {
    await this.initPlayer();
    return this.player;
  }

  setType(value: MediaType) {
    this.type = value;
  }

  setUrl(value: string) {
    this.url = value
  }

  setSurfaceID(value: string) {
    this.surfaceID = value
  }

  // 注册avplayer回调函数
  setAVPlayerCallback(avPlayer: media.AVPlayer) {
    // startRenderFrame首帧渲染回调函数
    avPlayer.on('startRenderFrame', () => {
      console.info(`AVPlayer start render frame`);
    })
    // error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程
    avPlayer.on('error', (err: BusinessError) => {
      console.error(`调用avPlayer失败, code is ${err.code}, message is ${err.message},mod:${this.type}`);
      avPlayer.reset(); // 调用reset重置资源,触发idle状态
    })
    // 状态机变化回调函数
    avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
      switch (state) {
        case 'idle': // 成功调用reset接口后触发该状态机上报
          console.info('zzz===, AVPlayer state idle called.');
          // avPlayer.release(); // 调用release接口销毁实例对象
          if (this.file.fd) {
            fs.close(this.file.fd)
          }
          break;
        case 'initialized': // avplayer 设置播放源后触发该状态上报
          console.info('zzz===, AVPlayer state initialized called.');
          if (this.type === MediaType.Video && this.surfaceID != null) {
            avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置
          }
          avPlayer.prepare();
          break;
        case 'prepared': // prepare调用成功后上报该状态机
          if (this.type === MediaType.Video) {
            let data: emitter.EventData = {
              data: {
                duration: avPlayer.duration
              }
            }
            emitter.emit('MediaPrepared', data);
          }
          if (this.type === MediaType.Audio) {
            emitter.emit('AudioPrepared');
          }
          // avPlayer.play()
          console.log(`@@@, duration: ${avPlayer.duration}`)
          break;
        case 'playing': // play成功调用后触发该状态机上报
          console.info('@@@, AVPlayer state playing called.');

          if (this.type === MediaType.Video) {
            emitter.emit('IsPlaying');
          }
          if (this.type === MediaType.Audio) {
            emitter.emit('IsAudioPlaying');
          }
          break;
        case 'paused': // pause成功调用后触发该状态机上报
          console.info('@@@, AVPlayer state paused called.');
          if (this.type === MediaType.Video) {
            emitter.emit('IsPaused');
          }
          break;
        case 'completed': // 播放结束后触发该状态机上报
          console.info('@@@, AVPlayer state completed called.');
          // avPlayer.stop(); //
          console.log('zzz=== 配音单播放结束')
          emitter.emit('IsCompleted');
          break;
        case 'stopped': // stop接口成功调用后触发该状态机上报
          console.info('@@@, AVPlayer state stopped called.');
          avPlayer.release(); // 调用reset接口初始化avplayer状态
          break;
        case 'released':
          console.info('@@@, AVPlayer state released called.');
          break;
        default:
          console.info('@@@, AVPlayer state unknown called.');
          break;
      }
    })
  }

  // 以下demo为通过url设置网络地址来实现播放直播码流的demo
  async avPlayerLive(): Promise<void> {
    // 创建avPlayer实例对象
    let avPlayer: media.AVPlayer = (await this.getPlayer())!;
    // 创建状态机变化回调函数
    this.setAVPlayerCallback(avPlayer);
    avPlayer.url = this.url // 播放hls网络直播码流
  }

  // 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过url属性进行播放示例
  async avPlayerUrl(savedAddress:string , setAVPlayerCallback?: (avPlayer: media.AVPlayer) => void) {
    // 创建avPlayer实例对象
    await this.getPlayer();
    // this.player = avPlayer;
    // 创建状态机变化回调函数
    if (setAVPlayerCallback !== undefined) {
      setAVPlayerCallback(this.player!)
    } else {
      this.setAVPlayerCallback(this.player!);
    }
    let fdPath = 'fd://';
    // 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例
    // let context = getContext(this) as common.UIAbilityContext;
    // let pathDir = context.filesDir;
    let path = getContext().filesDir + '/' + savedAddress + '.mp3';
    // 打开相应的资源文件地址获取fd,并为url赋值触发initialized状态机上报
    if(!fs.accessSync(path)) {
      // TODO:
      return;
    }
    this.file = await fs.open(path);
    fdPath = fdPath + '' + this.file.fd;
    this.isSeek = true; // 支持seek操作
    if(this.player !== null) {
      this.player.url = fdPath;
    }
  }
}
/**
 * 获取时分秒展示
 * @param {duration} 毫秒
 */
const GetTimeString = (duration: number) => {
  let time: number = parseInt((duration / 1000).toString());
  let second: number = parseFloat((time % 60).toFixed(0));
  let min: number = parseInt((time / 60).toString());
  let head = min < 10 ? `${0}${min}` : min;
  let end = second < 10 ? `${0}${second}` : second;
  let durationStringTime = `${head}:${end}`; //分/秒 显示
  return durationStringTime
}
/**
 * 秒转化为分秒显示
 * @param seconds
 * @returns
 */
const FormatSeconds = (seconds: number) => {
  const m = Math.floor((seconds % 3600) / 60);
  const s = seconds % 60;
  // 补0为两位数,拼接格式
  return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
}