wangyujian_wd

feat:1)直播详情页面直播间【音视频图文类型UI】重构;2)直播间跳转视频详情页面添加

... ... @@ -65,6 +65,8 @@ export function registerRouter() {
return WDRouterPage.audioDetail
} else if (action.params?.detailPageType == 18) {
return WDRouterPage.multiPictureListPage
} else if (action.params?.detailPageType == 19) {
return WDRouterPage.videoPlayPage
}else if (action.params?.detailPageType == 30) {
return WDRouterPage.themeListPage
}
... ...
... ... @@ -59,6 +59,8 @@ export class WDRouterPage {
static multiPictureDetailPage = new WDRouterPage("phone", "ets/pages/detail/MultiPictureDetailPage");
//大图列表页
static multiPictureListPage = new WDRouterPage("wdComponent", "ets/pages/MultiPictureListPage");
//单个视频播放页
static videoPlayPage = new WDRouterPage("wdComponent", "ets/pages/VideoPlayPage");
// 音乐详情页
static audioDetail = new WDRouterPage("phone", "ets/pages/detail/AudioDetail");
// 动态详情页
... ...
... ... @@ -19,7 +19,10 @@ export interface Params {
// 13.音频详情页
// 17.多图(图集)详情页
// 18.大图列表页
// 19.单个视频播放页
detailPageType?: number; // 详情页类型
liveStyle?: number; // 直播类型:0横屏,1竖屏
creatorId?: string; //号主id
videoUrl?: string;
videoCoverUrl?: string;
}
... ...
... ... @@ -16,4 +16,11 @@ export interface LiveRoomItemBean {
//是否置顶 1置顶0不置顶
isTop: number
role: string
//ZH_TEXT_AND_IMAGE_MSG :图文,ZH_TEXT_MSG:文本,ZH_VIDEO_MSG:视频,ZH_AUDIO_MSG:音频
dataType: string
transcodeImageUrl: string
videoUrl: string
pictureResolutions: string[]
//音视频长度
duration: number
}
\ No newline at end of file
... ...
import { DateFormatUtil, WDPlayerController, WDPlayerRenderLiveView } from 'wdPlayer/Index';
import router from '@ohos.router';
import { StringUtils } from 'wdKit/Index';
import { Action } from 'wdBean';
const TAG = 'VideoPlayPage';
@Entry
@Component
export struct VideoPlayPage {
//是否处于播放状态中
@State isPlayStatus: boolean = true
playerController: WDPlayerController = new WDPlayerController();
//视频地址
@State videoUrl: string = ''
//封面图
@State videoCoverUrl: string = ''
@State currentTime: string = ''
@State totalTime: string = ''
@State progressVal: number = 0;
aboutToAppear(): void {
let par: Action = router.getParams() as Action
let params = par?.params
this.videoUrl = params?.videoUrl ? params?.videoUrl : ''
this.videoCoverUrl = params?.videoCoverUrl ? params?.videoCoverUrl : ''
//播放进度监听
this.playerController.onTimeUpdate = (position: number, duration: number) => {
this.currentTime = DateFormatUtil.secondToTime(Math.floor(position / 1000));
this.totalTime = DateFormatUtil.secondToTime(Math.floor(duration / 1000));
this.progressVal = Math.floor(position * 100 / duration);
}
this.playerController.onCanplay = () => {
this.playerController.play()
}
}
build() {
Stack() {
WDPlayerRenderLiveView({
playerController: this.playerController,
onLoad: async () => {
this.playerController.firstPlay(this.videoUrl)
}
})
.height('100%')
.width('100%')
.visibility(StringUtils.isEmpty(this.videoUrl) ? Visibility.None : Visibility.Visible)
Image(this.videoCoverUrl)
.objectFit(ImageFit.Contain)
.visibility(StringUtils.isEmpty(this.videoUrl) ? Visibility.Visible : Visibility.None)
Column() {
this.getTopUIComponent()
Stack()
.layoutWeight(1)
this.getBottomUIComponent()
}
}
.width('100%')
}
@Builder
getTopUIComponent() {
Column() {
Row() {
Image($r('app.media.icon_arrow_left_white'))
.width(24)
.aspectRatio(1)
.margin({
right: 10
})
.onClick(() => {
router.back()
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
.margin({
bottom: 10
})
}.width('100%')
.padding({
top: 20,
bottom: 6,
left: 10,
right: 10
})
.alignItems(HorizontalAlign.Start)
}
@Builder
getBottomUIComponent() {
Row() {
this.playOrPauseBtn()
Text(this.currentTime)
.fontColor(Color.White)
.fontWeight(600)
.fontSize('12fp')
.margin({
left: 16
})
this.playProgressView()
Text(this.totalTime)
.fontColor(Color.White)
.fontWeight(600)
.fontSize('12fp')
.margin({
right: 16
})
}
.alignItems(VerticalAlign.Center)
.width('100%')
.padding({
left: 10,
right: 10,
top: 15,
bottom: 15
})
}
@Builder
playOrPauseBtn() {
//暂停、播放
Image(this.isPlayStatus ? $r('app.media.icon_live_player_pause') : $r('app.media.player_play_ic'))
.width(24)
.height(24)
.onClick(() => {
if (this.isPlayStatus) {
this.isPlayStatus = false
this.playerController.pause()
} else {
this.isPlayStatus = true
this.playerController.play()
}
})
}
@Builder
playProgressView() {
Slider({
value: this.progressVal,
step: 1,
style: SliderStyle.OutSet
})
.blockSize({
width: 18,
height: 12
})
.blockStyle({
type: SliderBlockType.IMAGE,
image: $r('app.media.ic_player_block')
})
.blockColor(Color.White)
.trackColor('#4DFFFFFF')
.selectedColor('#FFED2800')
.height(14)
.trackThickness(1)
.layoutWeight(1)
.margin({
left: 8,
right: 8
})
.onChange((value: number, mode: SliderChangeMode) => {
this.playerController?.setSeekTime(value, mode);
})
}
onPageHide(): void {
this.playerController?.pause()
this.playerController?.stop()
}
}
\ No newline at end of file
... ...
... ... @@ -20,6 +20,7 @@
"pages/MultiPictureListPage",
"components/page/LiveMorePage",
"components/page/ReserveMorePage",
"pages/VideoPlayPage",
"components/page/ThemeListPage"
]
}
\ No newline at end of file
... ...
import { LiveDetailsBean, LiveRoomItemBean } from 'wdBean/Index'
import { EmptyComponent, ErrorComponent, ListHasNoMoreDataUI, WDViewDefaultType } from 'wdComponent/Index'
import { EmptyComponent, ErrorComponent, WDViewDefaultType } from 'wdComponent/Index'
import CustomRefreshLoadLayout from 'wdComponent/src/main/ets/components/page/CustomRefreshLoadLayout'
import LoadMoreLayout from 'wdComponent/src/main/ets/components/page/LoadMoreLayout'
import RefreshLayout from 'wdComponent/src/main/ets/components/page/RefreshLayout'
import { RefreshLayoutBean } from 'wdComponent/src/main/ets/components/page/RefreshLayoutBean'
import PageModel from 'wdComponent/src/main/ets/viewmodel/PageModel'
import { ViewType } from 'wdConstant/Index'
import { Logger } from 'wdKit/Index'
import { LiveViewModel } from '../../viewModel/LiveViewModel'
import { TabChatItemComponent } from './TabChatItemComponent'
... ...
import { LiveDetailsBean, LiveRoomItemBean } from 'wdBean/Index'
import { EmptyComponent, ErrorComponent, ListHasNoMoreDataUI, WDViewDefaultType } from 'wdComponent/Index'
import { LiveViewModel } from '../../viewModel/LiveViewModel'
import { EmptyComponent, ErrorComponent, ListHasNoMoreDataUI,
WDViewDefaultType } from 'wdComponent/Index'
import { TabLiveItemComponent } from './TabLiveItemComponent'
import CustomRefreshLoadLayout from 'wdComponent/src/main/ets/components/page/CustomRefreshLoadLayout'
import { RefreshLayoutBean } from 'wdComponent/src/main/ets/components/page/RefreshLayoutBean'
... ... @@ -9,6 +9,7 @@ import { ViewType } from 'wdConstant/Index'
import LoadMoreLayout from 'wdComponent/src/main/ets/components/page/LoadMoreLayout'
import RefreshLayout from 'wdComponent/src/main/ets/components/page/RefreshLayout'
import { StringUtils } from 'wdKit/Index'
import { LiveViewModel } from '../../viewModel/LiveViewModel'
@Component
export struct TabLiveComponent {
... ... @@ -110,6 +111,7 @@ export struct TabLiveComponent {
liveRoomItemBeanTemp.senderUserName = '人民日报主持人'
liveRoomItemBeanTemp.pictureUrls=[]
liveRoomItemBeanTemp.pictureUrls.push(this.liveDetailsBean?.fullColumnImgUrls[0]?.url)
liveRoomItemBeanTemp.dataType='ZH_TEXT_AND_IMAGE_MSG'
this.liveList.push(liveRoomItemBeanTemp)
}
}
... ...
import { LiveRoomItemBean, PhotoListBean, } from 'wdBean/Index';
import { DateTimeUtils, StringUtils } from 'wdKit/Index';
import { Action, Params } from 'wdBean';
import { ExtraDTO } from 'wdBean/src/main/ets/bean/component/extra/ExtraDTO';
import { WDRouterRule } from 'wdRouter/Index';
import { Action, LiveRoomItemBean, Params, PhotoListBean } from 'wdBean/Index'
import { ExtraDTO } from 'wdBean/src/main/ets/bean/component/extra/ExtraDTO'
import { DateTimeUtils, StringUtils } from 'wdKit/Index'
import { WDRouterRule } from 'wdRouter/Index'
@Component
export struct TabLiveItemComponent {
... ... @@ -14,108 +13,190 @@ export struct TabLiveItemComponent {
}
build() {
Column() {
Row() {
Image(StringUtils.isEmpty(this.item.senderUserAvatarUrl) ? $r('app.media.default_head') : this.item.senderUserAvatarUrl)
.borderRadius(90)
.width(24)
.height(24)
Text(this.item.senderUserName)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Row() {
Image(StringUtils.isEmpty(this.item.senderUserAvatarUrl) ? $r('app.media.default_head') : this.item.senderUserAvatarUrl)
.borderRadius(90)
.width(24)
.height(24)
Column() {
Row() {
Text(this.item.senderUserName)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('14fp')
.fontWeight(400)
.fontColor('#222222')
Text('主持人')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('11fp')
.fontWeight(400)
.fontColor('#968562')
.backgroundColor('#F1EFEB')
.padding({
left: 4,
top: 1,
right: 4,
bottom: 1
})
.borderRadius(2)
.margin({ left: 8 })
.visibility('host' == this.item.role ? Visibility.Visible : Visibility.None)
Text(DateTimeUtils.getCommentTime(new Date(this.item.time).getTime()))
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('12fp')
.fontWeight(400)
.fontColor('#999999')
.margin({ left: 8 })
.visibility(StringUtils.isNotEmpty(this.item.time) ? Visibility.Visible : Visibility.None)
Text('置顶')
.fontSize('11fp')
.fontWeight(400)
.fontColor('#ED2800')
.backgroundColor('#F1EFEB')
.padding({
left: 4,
top: 1,
right: 4,
bottom: 1
})
.borderRadius(2)
.margin({ left: 8 })
.width(100)
.visibility(1 == this.item.isTop ? Visibility.Visible : Visibility.None)
}
Text(this.item.text)
.fontSize('14fp')
.fontWeight(400)
.fontColor('#222222')
.margin({ left: 8 })
Text('主持人')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('11fp')
.fontWeight(400)
.fontColor('#968562')
.backgroundColor('#F1EFEB')
.padding({
left: 4,
top: 1,
right: 4,
bottom: 1
.margin({
top: 6
})
.borderRadius(2)
.margin({ left: 8 })
.visibility('host' == this.item.role ? Visibility.Visible : Visibility.None)
Text(DateTimeUtils.getCommentTime(new Date(this.item.time).getTime()))
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('12fp')
.fontWeight(400)
.fontColor('#999999')
.margin({ left: 8 })
.visibility(StringUtils.isNotEmpty(this.item.time) ? Visibility.Visible : Visibility.None)
Blank()
Text('置顶')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('11fp')
.fontWeight(400)
.fontColor('#ED2800')
.backgroundColor('#F1EFEB')
.padding({
left: 4,
top: 1,
right: 4,
bottom: 1
.width('100%')
.textAlign(TextAlign.Start)
//ZH_TEXT_AND_IMAGE_MSG :图文,ZH_TEXT_MSG:文本,ZH_VIDEO_MSG:视频,ZH_AUDIO_MSG:音频
//图文
if (this.item.dataType === 'ZH_TEXT_AND_IMAGE_MSG') {
List({ space: this.item.pictureUrls.length == 1 ? 0 : 5 }) {
ForEach(this.item.pictureUrls, (item: string, index: number) => {
ListItem() {
Image(item)
.width(`${100 / this.item.pictureUrls.length}%`)
.height(this.item.pictureUrls.length > 1 ? 70 : 174)
.objectFit(ImageFit.Auto)
.borderRadius(4)
}.onClick(() => {
this.photoList = []
for (let item of this.item.pictureUrls) {
this.photoList.push({
width: 0,
height: 0,
picPath: item,
picDesc: ''
})
}
this.gotoMultipleListImagePage()
})
})
}
.listDirection(Axis.Horizontal)
.margin({
top: 8,
right: 16
})
.borderRadius(2)
.margin({ left: 8 })
.visibility(1 == this.item.isTop ? Visibility.Visible : Visibility.None)
}
.width('100%')
Text(this.item.text)
.fontSize('14fp')
.fontWeight(400)
.fontColor('#222222')
.margin({
left: 32,
top: 6
})
.width('100%')
.textAlign(TextAlign.Start)
List() {
ForEach(this.item.pictureUrls, (item: string, index: number) => {
ListItem() {
Image(item)
.height(174)
.width(310)
.aspectRatio(310 / 174)
.objectFit(ImageFit.Auto)
.borderRadius(4)
}.onClick(() => {
this.photoList=[]
for (let item of this.item.pictureUrls) {
this.photoList.push({
width: 0,
height: 0,
picPath: item,
picDesc: ''
}
//音频
else if (this.item.dataType === 'ZH_AUDIO_MSG') {
Row() {
Image($r('app.media.icon_voice'))
.width(20)
.aspectRatio(1)
.margin({
left: 8,
right: 6
})
Text(DateTimeUtils.getFormattedDuration(this.item.duration))
.fontColor('#666666')
.fontWeight(400)
.fontSize('14fp')
}
.backgroundColor(Color.White)
.height(36)
.borderRadius(4)
.margin({ top: 8, right: 16 })
.width('100%')
}
//视频
else if (this.item.dataType === 'ZH_VIDEO_MSG') {
RelativeContainer() {
Image(this.item.transcodeImageUrl)
.width('100%')
.objectFit(ImageFit.Cover)
.borderRadius(4)
.id('iv_id')
Stack() {
Row()
.borderRadius(90)
.width(32)
.height(32)
.backgroundColor('#000000')
Image($r('app.media.player_play_ic'))
.height(16)
.aspectRatio(1)
}
this.gotoMultipleListImagePage()
.alignRules({
left: { anchor: "iv_id", align: HorizontalAlign.Start },
bottom: { anchor: "iv_id", align: VerticalAlign.Bottom }
})
.margin({
left: 12,
bottom: 12
})
.id('play_id')
}
.margin({
top: 8,
right: 16
})
.aspectRatio(Number.parseFloat(this.item.pictureResolutions[0]?.split('*')[0]) / Number.parseFloat(this.item.pictureResolutions[0]?.split('*')[1]))
.onClick(() => {
this.gotoVideoPlayPage()
})
})
}.margin({
left: 32,
top: 8
}
}
.margin({
left: 8,
right: 16
})
}.margin({
left: 15,
top: 15,
right: 15
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.alignItems(VerticalAlign.Top)
.padding({
left: 17,
top: 8,
bottom: 8,
})
}
aboutToDisappear(): void {
/**
* @param content
* */
gotoVideoPlayPage() {
let taskAction: Action = {
type: 'JUMP_DETAIL_PAGE',
params: {
detailPageType: 19,
videoUrl: this.item.videoUrl,
videoCoverUrl: this.item.transcodeImageUrl
} as Params,
};
WDRouterRule.jumpWithAction(taskAction)
}
/**
... ... @@ -134,4 +215,8 @@ export struct TabLiveItemComponent {
};
WDRouterRule.jumpWithAction(taskAction)
}
aboutToDisappear(): void {
}
}
\ No newline at end of file
... ...
... ... @@ -269,7 +269,8 @@ export struct PlayUIComponent {
.blockSize({
width: 18,
height: 12
})// .blockStyle({
})
// .blockStyle({
// type: SliderBlockType.IMAGE,
// image: $r('app.media.ic_player_block')
// })
... ...