wangyujian_wd

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

@@ -65,6 +65,8 @@ export function registerRouter() { @@ -65,6 +65,8 @@ export function registerRouter() {
65 return WDRouterPage.audioDetail 65 return WDRouterPage.audioDetail
66 } else if (action.params?.detailPageType == 18) { 66 } else if (action.params?.detailPageType == 18) {
67 return WDRouterPage.multiPictureListPage 67 return WDRouterPage.multiPictureListPage
  68 + } else if (action.params?.detailPageType == 19) {
  69 + return WDRouterPage.videoPlayPage
68 }else if (action.params?.detailPageType == 30) { 70 }else if (action.params?.detailPageType == 30) {
69 return WDRouterPage.themeListPage 71 return WDRouterPage.themeListPage
70 } 72 }
@@ -59,6 +59,8 @@ export class WDRouterPage { @@ -59,6 +59,8 @@ export class WDRouterPage {
59 static multiPictureDetailPage = new WDRouterPage("phone", "ets/pages/detail/MultiPictureDetailPage"); 59 static multiPictureDetailPage = new WDRouterPage("phone", "ets/pages/detail/MultiPictureDetailPage");
60 //大图列表页 60 //大图列表页
61 static multiPictureListPage = new WDRouterPage("wdComponent", "ets/pages/MultiPictureListPage"); 61 static multiPictureListPage = new WDRouterPage("wdComponent", "ets/pages/MultiPictureListPage");
  62 + //单个视频播放页
  63 + static videoPlayPage = new WDRouterPage("wdComponent", "ets/pages/VideoPlayPage");
62 // 音乐详情页 64 // 音乐详情页
63 static audioDetail = new WDRouterPage("phone", "ets/pages/detail/AudioDetail"); 65 static audioDetail = new WDRouterPage("phone", "ets/pages/detail/AudioDetail");
64 // 动态详情页 66 // 动态详情页
@@ -19,7 +19,10 @@ export interface Params { @@ -19,7 +19,10 @@ export interface Params {
19 // 13.音频详情页 19 // 13.音频详情页
20 // 17.多图(图集)详情页 20 // 17.多图(图集)详情页
21 // 18.大图列表页 21 // 18.大图列表页
  22 + // 19.单个视频播放页
22 detailPageType?: number; // 详情页类型 23 detailPageType?: number; // 详情页类型
23 liveStyle?: number; // 直播类型:0横屏,1竖屏 24 liveStyle?: number; // 直播类型:0横屏,1竖屏
24 creatorId?: string; //号主id 25 creatorId?: string; //号主id
  26 + videoUrl?: string;
  27 + videoCoverUrl?: string;
25 } 28 }
@@ -16,4 +16,11 @@ export interface LiveRoomItemBean { @@ -16,4 +16,11 @@ export interface LiveRoomItemBean {
16 //是否置顶 1置顶0不置顶 16 //是否置顶 1置顶0不置顶
17 isTop: number 17 isTop: number
18 role: string 18 role: string
  19 + //ZH_TEXT_AND_IMAGE_MSG :图文,ZH_TEXT_MSG:文本,ZH_VIDEO_MSG:视频,ZH_AUDIO_MSG:音频
  20 + dataType: string
  21 + transcodeImageUrl: string
  22 + videoUrl: string
  23 + pictureResolutions: string[]
  24 + //音视频长度
  25 + duration: number
19 } 26 }
  1 +import { DateFormatUtil, WDPlayerController, WDPlayerRenderLiveView } from 'wdPlayer/Index';
  2 +import router from '@ohos.router';
  3 +import { StringUtils } from 'wdKit/Index';
  4 +import { Action } from 'wdBean';
  5 +
  6 +const TAG = 'VideoPlayPage';
  7 +
  8 +@Entry
  9 +@Component
  10 +export struct VideoPlayPage {
  11 + //是否处于播放状态中
  12 + @State isPlayStatus: boolean = true
  13 + playerController: WDPlayerController = new WDPlayerController();
  14 + //视频地址
  15 + @State videoUrl: string = ''
  16 + //封面图
  17 + @State videoCoverUrl: string = ''
  18 + @State currentTime: string = ''
  19 + @State totalTime: string = ''
  20 + @State progressVal: number = 0;
  21 +
  22 + aboutToAppear(): void {
  23 + let par: Action = router.getParams() as Action
  24 + let params = par?.params
  25 + this.videoUrl = params?.videoUrl ? params?.videoUrl : ''
  26 + this.videoCoverUrl = params?.videoCoverUrl ? params?.videoCoverUrl : ''
  27 + //播放进度监听
  28 + this.playerController.onTimeUpdate = (position: number, duration: number) => {
  29 + this.currentTime = DateFormatUtil.secondToTime(Math.floor(position / 1000));
  30 + this.totalTime = DateFormatUtil.secondToTime(Math.floor(duration / 1000));
  31 + this.progressVal = Math.floor(position * 100 / duration);
  32 + }
  33 + this.playerController.onCanplay = () => {
  34 + this.playerController.play()
  35 + }
  36 + }
  37 +
  38 + build() {
  39 + Stack() {
  40 + WDPlayerRenderLiveView({
  41 + playerController: this.playerController,
  42 + onLoad: async () => {
  43 + this.playerController.firstPlay(this.videoUrl)
  44 + }
  45 + })
  46 + .height('100%')
  47 + .width('100%')
  48 + .visibility(StringUtils.isEmpty(this.videoUrl) ? Visibility.None : Visibility.Visible)
  49 + Image(this.videoCoverUrl)
  50 + .objectFit(ImageFit.Contain)
  51 + .visibility(StringUtils.isEmpty(this.videoUrl) ? Visibility.Visible : Visibility.None)
  52 + Column() {
  53 + this.getTopUIComponent()
  54 + Stack()
  55 + .layoutWeight(1)
  56 + this.getBottomUIComponent()
  57 + }
  58 + }
  59 + .width('100%')
  60 + }
  61 +
  62 + @Builder
  63 + getTopUIComponent() {
  64 + Column() {
  65 + Row() {
  66 + Image($r('app.media.icon_arrow_left_white'))
  67 + .width(24)
  68 + .aspectRatio(1)
  69 + .margin({
  70 + right: 10
  71 + })
  72 + .onClick(() => {
  73 + router.back()
  74 + })
  75 + }
  76 + .width('100%')
  77 + .alignItems(VerticalAlign.Center)
  78 + .margin({
  79 + bottom: 10
  80 + })
  81 + }.width('100%')
  82 + .padding({
  83 + top: 20,
  84 + bottom: 6,
  85 + left: 10,
  86 + right: 10
  87 + })
  88 + .alignItems(HorizontalAlign.Start)
  89 + }
  90 +
  91 + @Builder
  92 + getBottomUIComponent() {
  93 + Row() {
  94 + this.playOrPauseBtn()
  95 + Text(this.currentTime)
  96 + .fontColor(Color.White)
  97 + .fontWeight(600)
  98 + .fontSize('12fp')
  99 + .margin({
  100 + left: 16
  101 + })
  102 + this.playProgressView()
  103 + Text(this.totalTime)
  104 + .fontColor(Color.White)
  105 + .fontWeight(600)
  106 + .fontSize('12fp')
  107 + .margin({
  108 + right: 16
  109 + })
  110 + }
  111 + .alignItems(VerticalAlign.Center)
  112 + .width('100%')
  113 + .padding({
  114 + left: 10,
  115 + right: 10,
  116 + top: 15,
  117 + bottom: 15
  118 + })
  119 + }
  120 +
  121 + @Builder
  122 + playOrPauseBtn() {
  123 + //暂停、播放
  124 + Image(this.isPlayStatus ? $r('app.media.icon_live_player_pause') : $r('app.media.player_play_ic'))
  125 + .width(24)
  126 + .height(24)
  127 + .onClick(() => {
  128 + if (this.isPlayStatus) {
  129 + this.isPlayStatus = false
  130 + this.playerController.pause()
  131 + } else {
  132 + this.isPlayStatus = true
  133 + this.playerController.play()
  134 + }
  135 + })
  136 + }
  137 +
  138 + @Builder
  139 + playProgressView() {
  140 + Slider({
  141 + value: this.progressVal,
  142 + step: 1,
  143 + style: SliderStyle.OutSet
  144 + })
  145 + .blockSize({
  146 + width: 18,
  147 + height: 12
  148 + })
  149 + .blockStyle({
  150 + type: SliderBlockType.IMAGE,
  151 + image: $r('app.media.ic_player_block')
  152 + })
  153 + .blockColor(Color.White)
  154 + .trackColor('#4DFFFFFF')
  155 + .selectedColor('#FFED2800')
  156 + .height(14)
  157 + .trackThickness(1)
  158 + .layoutWeight(1)
  159 + .margin({
  160 + left: 8,
  161 + right: 8
  162 + })
  163 + .onChange((value: number, mode: SliderChangeMode) => {
  164 + this.playerController?.setSeekTime(value, mode);
  165 + })
  166 + }
  167 +
  168 + onPageHide(): void {
  169 + this.playerController?.pause()
  170 + this.playerController?.stop()
  171 + }
  172 +}
@@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
20 "pages/MultiPictureListPage", 20 "pages/MultiPictureListPage",
21 "components/page/LiveMorePage", 21 "components/page/LiveMorePage",
22 "components/page/ReserveMorePage", 22 "components/page/ReserveMorePage",
  23 + "pages/VideoPlayPage",
23 "components/page/ThemeListPage" 24 "components/page/ThemeListPage"
24 ] 25 ]
25 } 26 }
1 import { LiveDetailsBean, LiveRoomItemBean } from 'wdBean/Index' 1 import { LiveDetailsBean, LiveRoomItemBean } from 'wdBean/Index'
2 -import { EmptyComponent, ErrorComponent, ListHasNoMoreDataUI, WDViewDefaultType } from 'wdComponent/Index' 2 +import { EmptyComponent, ErrorComponent, WDViewDefaultType } from 'wdComponent/Index'
3 import CustomRefreshLoadLayout from 'wdComponent/src/main/ets/components/page/CustomRefreshLoadLayout' 3 import CustomRefreshLoadLayout from 'wdComponent/src/main/ets/components/page/CustomRefreshLoadLayout'
4 -import LoadMoreLayout from 'wdComponent/src/main/ets/components/page/LoadMoreLayout'  
5 import RefreshLayout from 'wdComponent/src/main/ets/components/page/RefreshLayout' 4 import RefreshLayout from 'wdComponent/src/main/ets/components/page/RefreshLayout'
6 import { RefreshLayoutBean } from 'wdComponent/src/main/ets/components/page/RefreshLayoutBean' 5 import { RefreshLayoutBean } from 'wdComponent/src/main/ets/components/page/RefreshLayoutBean'
7 import PageModel from 'wdComponent/src/main/ets/viewmodel/PageModel' 6 import PageModel from 'wdComponent/src/main/ets/viewmodel/PageModel'
8 import { ViewType } from 'wdConstant/Index' 7 import { ViewType } from 'wdConstant/Index'
9 -import { Logger } from 'wdKit/Index'  
10 import { LiveViewModel } from '../../viewModel/LiveViewModel' 8 import { LiveViewModel } from '../../viewModel/LiveViewModel'
11 import { TabChatItemComponent } from './TabChatItemComponent' 9 import { TabChatItemComponent } from './TabChatItemComponent'
12 10
1 import { LiveDetailsBean, LiveRoomItemBean } from 'wdBean/Index' 1 import { LiveDetailsBean, LiveRoomItemBean } from 'wdBean/Index'
2 -import { EmptyComponent, ErrorComponent, ListHasNoMoreDataUI, WDViewDefaultType } from 'wdComponent/Index'  
3 -import { LiveViewModel } from '../../viewModel/LiveViewModel' 2 +import { EmptyComponent, ErrorComponent, ListHasNoMoreDataUI,
  3 + WDViewDefaultType } from 'wdComponent/Index'
4 import { TabLiveItemComponent } from './TabLiveItemComponent' 4 import { TabLiveItemComponent } from './TabLiveItemComponent'
5 import CustomRefreshLoadLayout from 'wdComponent/src/main/ets/components/page/CustomRefreshLoadLayout' 5 import CustomRefreshLoadLayout from 'wdComponent/src/main/ets/components/page/CustomRefreshLoadLayout'
6 import { RefreshLayoutBean } from 'wdComponent/src/main/ets/components/page/RefreshLayoutBean' 6 import { RefreshLayoutBean } from 'wdComponent/src/main/ets/components/page/RefreshLayoutBean'
@@ -9,6 +9,7 @@ import { ViewType } from 'wdConstant/Index' @@ -9,6 +9,7 @@ import { ViewType } from 'wdConstant/Index'
9 import LoadMoreLayout from 'wdComponent/src/main/ets/components/page/LoadMoreLayout' 9 import LoadMoreLayout from 'wdComponent/src/main/ets/components/page/LoadMoreLayout'
10 import RefreshLayout from 'wdComponent/src/main/ets/components/page/RefreshLayout' 10 import RefreshLayout from 'wdComponent/src/main/ets/components/page/RefreshLayout'
11 import { StringUtils } from 'wdKit/Index' 11 import { StringUtils } from 'wdKit/Index'
  12 +import { LiveViewModel } from '../../viewModel/LiveViewModel'
12 13
13 @Component 14 @Component
14 export struct TabLiveComponent { 15 export struct TabLiveComponent {
@@ -110,6 +111,7 @@ export struct TabLiveComponent { @@ -110,6 +111,7 @@ export struct TabLiveComponent {
110 liveRoomItemBeanTemp.senderUserName = '人民日报主持人' 111 liveRoomItemBeanTemp.senderUserName = '人民日报主持人'
111 liveRoomItemBeanTemp.pictureUrls=[] 112 liveRoomItemBeanTemp.pictureUrls=[]
112 liveRoomItemBeanTemp.pictureUrls.push(this.liveDetailsBean?.fullColumnImgUrls[0]?.url) 113 liveRoomItemBeanTemp.pictureUrls.push(this.liveDetailsBean?.fullColumnImgUrls[0]?.url)
  114 + liveRoomItemBeanTemp.dataType='ZH_TEXT_AND_IMAGE_MSG'
113 this.liveList.push(liveRoomItemBeanTemp) 115 this.liveList.push(liveRoomItemBeanTemp)
114 } 116 }
115 } 117 }
1 -import { LiveRoomItemBean, PhotoListBean, } from 'wdBean/Index';  
2 -import { DateTimeUtils, StringUtils } from 'wdKit/Index';  
3 -import { Action, Params } from 'wdBean';  
4 -import { ExtraDTO } from 'wdBean/src/main/ets/bean/component/extra/ExtraDTO';  
5 -import { WDRouterRule } from 'wdRouter/Index'; 1 +import { Action, LiveRoomItemBean, Params, PhotoListBean } from 'wdBean/Index'
  2 +import { ExtraDTO } from 'wdBean/src/main/ets/bean/component/extra/ExtraDTO'
  3 +import { DateTimeUtils, StringUtils } from 'wdKit/Index'
  4 +import { WDRouterRule } from 'wdRouter/Index'
6 5
7 @Component 6 @Component
8 export struct TabLiveItemComponent { 7 export struct TabLiveItemComponent {
@@ -14,19 +13,20 @@ export struct TabLiveItemComponent { @@ -14,19 +13,20 @@ export struct TabLiveItemComponent {
14 } 13 }
15 14
16 build() { 15 build() {
17 - Column() {  
18 Row() { 16 Row() {
19 Image(StringUtils.isEmpty(this.item.senderUserAvatarUrl) ? $r('app.media.default_head') : this.item.senderUserAvatarUrl) 17 Image(StringUtils.isEmpty(this.item.senderUserAvatarUrl) ? $r('app.media.default_head') : this.item.senderUserAvatarUrl)
20 .borderRadius(90) 18 .borderRadius(90)
21 .width(24) 19 .width(24)
22 .height(24) 20 .height(24)
  21 +
  22 + Column() {
  23 + Row() {
23 Text(this.item.senderUserName) 24 Text(this.item.senderUserName)
24 .maxLines(1) 25 .maxLines(1)
25 .textOverflow({ overflow: TextOverflow.Ellipsis }) 26 .textOverflow({ overflow: TextOverflow.Ellipsis })
26 .fontSize('14fp') 27 .fontSize('14fp')
27 .fontWeight(400) 28 .fontWeight(400)
28 .fontColor('#222222') 29 .fontColor('#222222')
29 - .margin({ left: 8 })  
30 Text('主持人') 30 Text('主持人')
31 .maxLines(1) 31 .maxLines(1)
32 .textOverflow({ overflow: TextOverflow.Ellipsis }) 32 .textOverflow({ overflow: TextOverflow.Ellipsis })
@@ -51,10 +51,8 @@ export struct TabLiveItemComponent { @@ -51,10 +51,8 @@ export struct TabLiveItemComponent {
51 .fontColor('#999999') 51 .fontColor('#999999')
52 .margin({ left: 8 }) 52 .margin({ left: 8 })
53 .visibility(StringUtils.isNotEmpty(this.item.time) ? Visibility.Visible : Visibility.None) 53 .visibility(StringUtils.isNotEmpty(this.item.time) ? Visibility.Visible : Visibility.None)
54 - Blank() 54 +
55 Text('置顶') 55 Text('置顶')
56 - .maxLines(1)  
57 - .textOverflow({ overflow: TextOverflow.Ellipsis })  
58 .fontSize('11fp') 56 .fontSize('11fp')
59 .fontWeight(400) 57 .fontWeight(400)
60 .fontColor('#ED2800') 58 .fontColor('#ED2800')
@@ -67,31 +65,32 @@ export struct TabLiveItemComponent { @@ -67,31 +65,32 @@ export struct TabLiveItemComponent {
67 }) 65 })
68 .borderRadius(2) 66 .borderRadius(2)
69 .margin({ left: 8 }) 67 .margin({ left: 8 })
  68 + .width(100)
70 .visibility(1 == this.item.isTop ? Visibility.Visible : Visibility.None) 69 .visibility(1 == this.item.isTop ? Visibility.Visible : Visibility.None)
71 } 70 }
72 - .width('100%')  
73 71
74 Text(this.item.text) 72 Text(this.item.text)
75 .fontSize('14fp') 73 .fontSize('14fp')
76 .fontWeight(400) 74 .fontWeight(400)
77 .fontColor('#222222') 75 .fontColor('#222222')
78 .margin({ 76 .margin({
79 - left: 32,  
80 top: 6 77 top: 6
81 }) 78 })
82 .width('100%') 79 .width('100%')
83 .textAlign(TextAlign.Start) 80 .textAlign(TextAlign.Start)
84 - List() { 81 + //ZH_TEXT_AND_IMAGE_MSG :图文,ZH_TEXT_MSG:文本,ZH_VIDEO_MSG:视频,ZH_AUDIO_MSG:音频
  82 + //图文
  83 + if (this.item.dataType === 'ZH_TEXT_AND_IMAGE_MSG') {
  84 + List({ space: this.item.pictureUrls.length == 1 ? 0 : 5 }) {
85 ForEach(this.item.pictureUrls, (item: string, index: number) => { 85 ForEach(this.item.pictureUrls, (item: string, index: number) => {
86 ListItem() { 86 ListItem() {
87 Image(item) 87 Image(item)
88 - .height(174)  
89 - .width(310)  
90 - .aspectRatio(310 / 174) 88 + .width(`${100 / this.item.pictureUrls.length}%`)
  89 + .height(this.item.pictureUrls.length > 1 ? 70 : 174)
91 .objectFit(ImageFit.Auto) 90 .objectFit(ImageFit.Auto)
92 .borderRadius(4) 91 .borderRadius(4)
93 }.onClick(() => { 92 }.onClick(() => {
94 - this.photoList=[] 93 + this.photoList = []
95 for (let item of this.item.pictureUrls) { 94 for (let item of this.item.pictureUrls) {
96 this.photoList.push({ 95 this.photoList.push({
97 width: 0, 96 width: 0,
@@ -103,19 +102,101 @@ export struct TabLiveItemComponent { @@ -103,19 +102,101 @@ export struct TabLiveItemComponent {
103 this.gotoMultipleListImagePage() 102 this.gotoMultipleListImagePage()
104 }) 103 })
105 }) 104 })
106 - }.margin({  
107 - left: 32,  
108 - top: 8 105 + }
  106 + .listDirection(Axis.Horizontal)
  107 + .margin({
  108 + top: 8,
  109 + right: 16
  110 + })
  111 + }
  112 + //音频
  113 + else if (this.item.dataType === 'ZH_AUDIO_MSG') {
  114 + Row() {
  115 + Image($r('app.media.icon_voice'))
  116 + .width(20)
  117 + .aspectRatio(1)
  118 + .margin({
  119 + left: 8,
  120 + right: 6
  121 + })
  122 + Text(DateTimeUtils.getFormattedDuration(this.item.duration))
  123 + .fontColor('#666666')
  124 + .fontWeight(400)
  125 + .fontSize('14fp')
  126 + }
  127 + .backgroundColor(Color.White)
  128 + .height(36)
  129 + .borderRadius(4)
  130 + .margin({ top: 8, right: 16 })
  131 + .width('100%')
  132 + }
  133 + //视频
  134 + else if (this.item.dataType === 'ZH_VIDEO_MSG') {
  135 + RelativeContainer() {
  136 + Image(this.item.transcodeImageUrl)
  137 + .width('100%')
  138 + .objectFit(ImageFit.Cover)
  139 + .borderRadius(4)
  140 + .id('iv_id')
  141 + Stack() {
  142 + Row()
  143 + .borderRadius(90)
  144 + .width(32)
  145 + .height(32)
  146 + .backgroundColor('#000000')
  147 + Image($r('app.media.player_play_ic'))
  148 + .height(16)
  149 + .aspectRatio(1)
  150 + }
  151 + .alignRules({
  152 + left: { anchor: "iv_id", align: HorizontalAlign.Start },
  153 + bottom: { anchor: "iv_id", align: VerticalAlign.Bottom }
  154 + })
  155 + .margin({
  156 + left: 12,
  157 + bottom: 12
  158 + })
  159 + .id('play_id')
  160 + }
  161 + .margin({
  162 + top: 8,
  163 + right: 16
109 }) 164 })
110 - }.margin({  
111 - left: 15,  
112 - top: 15,  
113 - right: 15 165 + .aspectRatio(Number.parseFloat(this.item.pictureResolutions[0]?.split('*')[0]) / Number.parseFloat(this.item.pictureResolutions[0]?.split('*')[1]))
  166 + .onClick(() => {
  167 + this.gotoVideoPlayPage()
114 }) 168 })
115 } 169 }
116 170
117 - aboutToDisappear(): void { 171 + }
  172 + .margin({
  173 + left: 8,
  174 + right: 16
  175 + })
  176 + .layoutWeight(1)
  177 + .alignItems(HorizontalAlign.Start)
  178 + }
  179 + .alignItems(VerticalAlign.Top)
  180 + .padding({
  181 + left: 17,
  182 + top: 8,
  183 + bottom: 8,
  184 + })
  185 + }
118 186
  187 + /**
  188 + * @param content
  189 + * */
  190 + gotoVideoPlayPage() {
  191 + let taskAction: Action = {
  192 + type: 'JUMP_DETAIL_PAGE',
  193 + params: {
  194 + detailPageType: 19,
  195 + videoUrl: this.item.videoUrl,
  196 + videoCoverUrl: this.item.transcodeImageUrl
  197 + } as Params,
  198 + };
  199 + WDRouterRule.jumpWithAction(taskAction)
119 } 200 }
120 201
121 /** 202 /**
@@ -134,4 +215,8 @@ export struct TabLiveItemComponent { @@ -134,4 +215,8 @@ export struct TabLiveItemComponent {
134 }; 215 };
135 WDRouterRule.jumpWithAction(taskAction) 216 WDRouterRule.jumpWithAction(taskAction)
136 } 217 }
  218 +
  219 + aboutToDisappear(): void {
  220 +
  221 + }
137 } 222 }
@@ -269,7 +269,8 @@ export struct PlayUIComponent { @@ -269,7 +269,8 @@ export struct PlayUIComponent {
269 .blockSize({ 269 .blockSize({
270 width: 18, 270 width: 18,
271 height: 12 271 height: 12
272 - })// .blockStyle({ 272 + })
  273 + // .blockStyle({
273 // type: SliderBlockType.IMAGE, 274 // type: SliderBlockType.IMAGE,
274 // image: $r('app.media.ic_player_block') 275 // image: $r('app.media.ic_player_block')
275 // }) 276 // })