zhenghy

视频全屏

1 -import { BottomNavi, CommonConstants } from 'wdConstant'; 1 +import { BottomNavi, CommonConstants, DisplayDirection } from 'wdConstant';
2 import { BottomNavDTO, NavigationBodyDTO, NavigationDetailDTO, TopNavDTO } from 'wdBean'; 2 import { BottomNavDTO, NavigationBodyDTO, NavigationDetailDTO, TopNavDTO } from 'wdBean';
3 import { EmitterEventId, EmitterUtils, Logger, StringUtils } from 'wdKit'; 3 import { EmitterEventId, EmitterUtils, Logger, StringUtils } from 'wdKit';
4 import { TopNavigationComponent } from './TopNavigationComponent'; 4 import { TopNavigationComponent } from './TopNavigationComponent';
@@ -21,6 +21,7 @@ export struct BottomNavigationComponent { @@ -21,6 +21,7 @@ export struct BottomNavigationComponent {
21 @Provide bottomRectHeight: number = 0 21 @Provide bottomRectHeight: number = 0
22 @Provide topRectHeight: number = 0 22 @Provide topRectHeight: number = 0
23 @Provide isLayoutFullScreen: boolean = false 23 @Provide isLayoutFullScreen: boolean = false
  24 + @Provide displayDirection: DisplayDirection = DisplayDirection.VERTICAL
24 @Provide isImmersive: boolean = false // 是否开启沉浸式模式 http://192.168.1.3:3300/project/3802/interface/api/189229 25 @Provide isImmersive: boolean = false // 是否开启沉浸式模式 http://192.168.1.3:3300/project/3802/interface/api/189229
25 @Provide isNight: boolean = false // 是否开启夜间模式 26 @Provide isNight: boolean = false // 是否开启夜间模式
26 @Provide currentBottomNavInfo: BottomNavDTO = {} as BottomNavDTO; // 当前底导信息 27 @Provide currentBottomNavInfo: BottomNavDTO = {} as BottomNavDTO; // 当前底导信息
@@ -73,7 +74,7 @@ export struct BottomNavigationComponent { @@ -73,7 +74,7 @@ export struct BottomNavigationComponent {
73 TabContent() { 74 TabContent() {
74 if (CompUtils.isMine(navItem)) { 75 if (CompUtils.isMine(navItem)) {
75 // 我的页面组件数据列表 76 // 我的页面组件数据列表
76 - MinePageComponent({isMinePage: this.currentNavIndex === this.bottomNavList.length-1}) 77 + MinePageComponent({ isMinePage: this.currentNavIndex === this.bottomNavList.length - 1 })
77 } else if (navItem.name === '视频') { 78 } else if (navItem.name === '视频') {
78 // 视频频道,包含视频和直播 79 // 视频频道,包含视频和直播
79 VideoChannelPage({ 80 VideoChannelPage({
@@ -102,7 +103,8 @@ export struct BottomNavigationComponent { @@ -102,7 +103,8 @@ export struct BottomNavigationComponent {
102 .zIndex(10) 103 .zIndex(10)
103 .scrollable(false) 104 .scrollable(false)
104 .animationDuration(0) 105 .animationDuration(0)
105 - .barHeight($r('app.float.bottom_navigation_barHeight')) 106 + .barHeight(this.displayDirection === DisplayDirection.VERTICAL ? $r('app.float.bottom_navigation_barHeight') :
  107 + 0.001)
106 .barMode(BarMode.Fixed) 108 .barMode(BarMode.Fixed)
107 .barBackgroundColor(this.barBackgroundColor) 109 .barBackgroundColor(this.barBackgroundColor)
108 // 备注:鸿蒙目前只有修改三线导航背景方法,对于全面屏导航条手机需要设置背景色并使其扩散到导航区域 110 // 备注:鸿蒙目前只有修改三线导航背景方法,对于全面屏导航条手机需要设置背景色并使其扩散到导航区域
@@ -137,6 +139,7 @@ export struct BottomNavigationComponent { @@ -137,6 +139,7 @@ export struct BottomNavigationComponent {
137 .zIndex(10) 139 .zIndex(10)
138 .height($r('app.float.bottom_navigation_barHeight')) 140 .height($r('app.float.bottom_navigation_barHeight'))
139 .hoverEffect(HoverEffect.Highlight) 141 .hoverEffect(HoverEffect.Highlight)
  142 + .visibility(this.displayDirection === DisplayDirection.VERTICAL ? Visibility.Visible : Visibility.None)
140 .onClick(() => { 143 .onClick(() => {
141 Logger.info(TAG, `onChange, index: ${index}`); 144 Logger.info(TAG, `onChange, index: ${index}`);
142 this.onBottomNavigationIndexChange(navItem, index) 145 this.onBottomNavigationIndexChange(navItem, index)
@@ -6,6 +6,7 @@ import { BottomNavDTO, TopNavDTO } from 'wdBean/Index' @@ -6,6 +6,7 @@ import { BottomNavDTO, TopNavDTO } from 'wdBean/Index'
6 import { VideoChannelDetail } from 'wdDetailPlayShortVideo/Index'; 6 import { VideoChannelDetail } from 'wdDetailPlayShortVideo/Index';
7 import { PageComponent } from './PageComponent'; 7 import { PageComponent } from './PageComponent';
8 import { WDRouterPage, WDRouterRule } from 'wdRouter'; 8 import { WDRouterPage, WDRouterRule } from 'wdRouter';
  9 +import { DisplayDirection } from 'wdConstant/Index';
9 10
10 const TAG = 'VideoChannelPage' 11 const TAG = 'VideoChannelPage'
11 12
@@ -19,6 +20,7 @@ export struct VideoChannelPage { @@ -19,6 +20,7 @@ export struct VideoChannelPage {
19 @Prop topNavList: TopNavDTO[] 20 @Prop topNavList: TopNavDTO[]
20 @Link _currentNavIndex?: number; 21 @Link _currentNavIndex?: number;
21 @Consume barBackgroundColor: Color 22 @Consume barBackgroundColor: Color
  23 + @Consume displayDirection: DisplayDirection
22 @Consume @Watch('setBarBackgroundColor') currentBottomNavInfo: BottomNavDTO // 当前底导信息 24 @Consume @Watch('setBarBackgroundColor') currentBottomNavInfo: BottomNavDTO // 当前底导信息
23 @State @Watch('setBarBackgroundColor') currentTopNavSelectedIndex: number = 0; 25 @State @Watch('setBarBackgroundColor') currentTopNavSelectedIndex: number = 0;
24 @State animationDuration: number = 0 26 @State animationDuration: number = 0
@@ -68,7 +70,7 @@ export struct VideoChannelPage { @@ -68,7 +70,7 @@ export struct VideoChannelPage {
68 70
69 @Builder 71 @Builder
70 topNavView() { 72 topNavView() {
71 - Stack({alignContent: Alignment.TopEnd}) { 73 + Stack({ alignContent: Alignment.TopEnd }) {
72 Row() { 74 Row() {
73 ForEach(this.topNavList, (item: TopNavDTO, index: number) => { 75 ForEach(this.topNavList, (item: TopNavDTO, index: number) => {
74 Column() { 76 Column() {
@@ -127,6 +129,8 @@ export struct VideoChannelPage { @@ -127,6 +129,8 @@ export struct VideoChannelPage {
127 .backgroundColor(Color.Transparent) 129 .backgroundColor(Color.Transparent)
128 130
129 } 131 }
  132 + .zIndex(20)
  133 + .visibility(this.displayDirection === DisplayDirection.VERTICAL ? Visibility.Visible : Visibility.None)
130 134
131 } 135 }
132 136
1 import { ContentDetailDTO, InteractDataDTO } from 'wdBean'; 1 import { ContentDetailDTO, InteractDataDTO } from 'wdBean';
2 -import { WDPlayerController, WDPlayerRenderView } from 'wdPlayer'; 2 +import { PlayerConstants, WDPlayerController, WDPlayerRenderView } from 'wdPlayer';
3 import { ContentDetailRequest } from 'wdDetailPlayApi'; 3 import { ContentDetailRequest } from 'wdDetailPlayApi';
4 import { 4 import {
5 batchLikeAndCollectParams, 5 batchLikeAndCollectParams,
@@ -18,6 +18,7 @@ import { PlayerRightView } from '../view/PlayerRightView'; @@ -18,6 +18,7 @@ import { PlayerRightView } from '../view/PlayerRightView';
18 import { DisplayDirection } from 'wdConstant/Index'; 18 import { DisplayDirection } from 'wdConstant/Index';
19 import { CommentDialogView } from '../view/CommentDialogView'; 19 import { CommentDialogView } from '../view/CommentDialogView';
20 import { window } from '@kit.ArkUI'; 20 import { window } from '@kit.ArkUI';
  21 +import { PlayerFullScreenView } from '../view/PlayerFullScreenView';
21 22
22 const TAG = 'DetailPlayShortVideoPage'; 23 const TAG = 'DetailPlayShortVideoPage';
23 24
@@ -40,6 +41,7 @@ export struct DetailPlayShortVideoPage { @@ -40,6 +41,7 @@ export struct DetailPlayShortVideoPage {
40 @Provide followStatus: string = '0' // 关注状态 41 @Provide followStatus: string = '0' // 关注状态
41 @Provide isOpenDetail: boolean = false // 查看详情按钮点击 42 @Provide isOpenDetail: boolean = false // 查看详情按钮点击
42 @Provide isDragging: boolean = false // 拖动时间进度条 43 @Provide isDragging: boolean = false // 拖动时间进度条
  44 + @Provide status: number = PlayerConstants.STATUS_START;
43 @Consume showCommentList: boolean 45 @Consume showCommentList: boolean
44 @Consume displayDirection: DisplayDirection 46 @Consume displayDirection: DisplayDirection
45 @Consume @Watch('videoStatusChange') switchVideoStatus: boolean 47 @Consume @Watch('videoStatusChange') switchVideoStatus: boolean
@@ -254,16 +256,23 @@ export struct DetailPlayShortVideoPage { @@ -254,16 +256,23 @@ export struct DetailPlayShortVideoPage {
254 } 256 }
255 } 257 }
256 }) 258 })
257 - .width('100%')  
258 - .height(this.windowWidth / this.ratio + 'px') 259 + .width(this.displayDirection === DisplayDirection.VERTICAL ? '100%' : this.windowWidth * 16 / 9 + 'px')
  260 + .height(this.displayDirection === DisplayDirection.VERTICAL ? this.windowWidth / this.ratio + 'px' : '100%')
259 261
260 this.playerCoverBuilder() 262 this.playerCoverBuilder()
261 263
262 // 横屏-全屏观看 264 // 横屏-全屏观看
263 // 点击查看详情 不展示 265 // 点击查看详情 不展示
264 - if (this.videoLandScape === 1 && !this.isOpenDetail) { 266 + if (this.videoLandScape === 1 && !this.isOpenDetail && this.displayDirection === DisplayDirection.VERTICAL) {
265 this.playerFullscreenBuilder() 267 this.playerFullscreenBuilder()
266 } 268 }
  269 +
  270 + if (this.displayDirection === DisplayDirection.VIDEO_HORIZONTAL && this.index === this.currentIndex) {
  271 + PlayerFullScreenView({
  272 + playerController: this.playerController
  273 + })
  274 + }
  275 +
267 } 276 }
268 .width('100%') 277 .width('100%')
269 .height('100%') 278 .height('100%')
@@ -296,7 +305,7 @@ export struct DetailPlayShortVideoPage { @@ -296,7 +305,7 @@ export struct DetailPlayShortVideoPage {
296 .onClick(() => { 305 .onClick(() => {
297 // 全屏方案待定 306 // 全屏方案待定
298 // this.displayDirection = DisplayDirection.VERTICAL 307 // this.displayDirection = DisplayDirection.VERTICAL
299 - this.displayDirection = this.displayDirection == DisplayDirection.VERTICAL ? 308 + this.displayDirection = this.displayDirection === DisplayDirection.VERTICAL ?
300 DisplayDirection.VIDEO_HORIZONTAL : 309 DisplayDirection.VIDEO_HORIZONTAL :
301 DisplayDirection.VERTICAL 310 DisplayDirection.VERTICAL
302 WindowModel.shared.setPreferredOrientation(this.displayDirection == DisplayDirection.VERTICAL ? 311 WindowModel.shared.setPreferredOrientation(this.displayDirection == DisplayDirection.VERTICAL ?
@@ -52,7 +52,8 @@ export struct VideoChannelDetail { @@ -52,7 +52,8 @@ export struct VideoChannelDetail {
52 @Consume @Watch('pageShowChange') pageShow: number 52 @Consume @Watch('pageShowChange') pageShow: number
53 @Consume @Watch('pageHideChange') pageHide: number 53 @Consume @Watch('pageHideChange') pageHide: number
54 @Provide switchVideoStatus: boolean = true 54 @Provide switchVideoStatus: boolean = true
55 - @Provide displayDirection: DisplayDirection = DisplayDirection.VERTICAL 55 + // @Provide displayDirection: DisplayDirection = DisplayDirection.VERTICAL
  56 + @Consume displayDirection: DisplayDirection
56 @Provide showCommentList: boolean = false 57 @Provide showCommentList: boolean = false
57 @State data: ContentDetailDTO[] = [] 58 @State data: ContentDetailDTO[] = []
58 @State currentIndex: number = 0 59 @State currentIndex: number = 0
  1 +import { ContentDetailDTO } from 'wdBean/Index'
  2 +import { WDShare } from 'wdShare/Index'
  3 +import { PlayerProgressFullScreenView } from './PlayerProgressFullScreenView'
  4 +import { PlayerConstants, WDPlayerController } from 'wdPlayer/Index'
  5 +import { DateTimeUtils, WindowModel } from 'wdKit/Index'
  6 +import { DisplayDirection } from 'wdConstant/Index'
  7 +import { window } from '@kit.ArkUI'
  8 +
  9 +@Component
  10 +export struct PlayerFullScreenView {
  11 + private playerController?: WDPlayerController;
  12 + @Consume contentDetailData: ContentDetailDTO
  13 + @Consume progressVal: number;
  14 + @Consume status: number
  15 + @Consume displayDirection: DisplayDirection
  16 + @Consume isDragging: boolean
  17 + @State videoDuration: number = this.contentDetailData?.videoInfo?.[0]?.videoDuration || 1
  18 + @State showOperator: boolean = true
  19 + private timer: number = -1
  20 +
  21 + getTitle() {
  22 + return this.contentDetailData?.newsTitle
  23 + // || this.contentDetailData?.newsSummary || ''
  24 + }
  25 +
  26 + share() {
  27 + WDShare.shareContent(this.contentDetailData)
  28 + }
  29 +
  30 + aboutToAppear(): void {
  31 + WindowModel.shared.setWindowSystemBarEnable([])
  32 + this.timer = setInterval(() => {
  33 + this.showOperator = false
  34 + }, 5)
  35 + }
  36 +
  37 + aboutToDisappear(): void {
  38 + WindowModel.shared.setWindowSystemBarEnable(['status', 'navigation'])
  39 + clearInterval(this.timer)
  40 + }
  41 +
  42 + restartTimer() {
  43 + clearInterval(this.timer)
  44 + this.timer = setInterval(() => {
  45 + this.showOperator = false
  46 + }, 5)
  47 + }
  48 +
  49 + build() {
  50 + Stack() {
  51 + this.headerBuilder()
  52 +
  53 + this.bottomBuilder()
  54 + }
  55 + .zIndex(99999)
  56 + .height('100%')
  57 + .width('100%')
  58 + .onClick(() => {
  59 + this.restartTimer()
  60 + })
  61 + }
  62 +
  63 + @Builder
  64 + headerBuilder() {
  65 + Row() {
  66 + Row() {
  67 + Image($r(`app.media.ic_back`)).height(24).width(24)
  68 + .onClick(() => {
  69 + this.displayDirection = this.displayDirection == DisplayDirection.VERTICAL ?
  70 + DisplayDirection.VIDEO_HORIZONTAL :
  71 + DisplayDirection.VERTICAL
  72 + WindowModel.shared.setPreferredOrientation(this.displayDirection == DisplayDirection.VERTICAL ?
  73 + window.Orientation.PORTRAIT :
  74 + window.Orientation.LANDSCAPE_INVERTED)
  75 + })
  76 + Text(this.getTitle())
  77 + .fontSize(18)
  78 + .fontColor(Color.White)
  79 + .maxLines(1)
  80 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  81 + .margin({ left: 10 })
  82 + }
  83 +
  84 + Image($r(`app.media.ic_share`)).height(24).width(24)
  85 + .onClick(() => {
  86 + this.share()
  87 + })
  88 +
  89 + }
  90 + .width('100%')
  91 + .position({ x: 0, y: 0 })
  92 + .align(Alignment.Top)
  93 + .height(73)
  94 + .alignItems(VerticalAlign.Center)
  95 + .justifyContent(FlexAlign.SpaceBetween)
  96 + .padding({ left: 40, right: 40 })
  97 + .linearGradient({
  98 + direction: GradientDirection.Bottom, // 渐变方向
  99 + colors: [['rgba(0,0,0,0.5)', 0],
  100 + ['rgba(1,1,1,0)', 1.0]] // 数组末尾元素占比小于1时满足重复着色效果
  101 + })
  102 + }
  103 +
  104 + @Builder
  105 + bottomBuilder() {
  106 +
  107 + Column() {
  108 + Text() {
  109 + Span(DateTimeUtils.secondToTime(Math.floor(this.progressVal / 100 * this.videoDuration)))
  110 + Span(' / ')
  111 + Span(DateTimeUtils.secondToTime(this.videoDuration))
  112 + }
  113 + .fontSize(24)
  114 + .fontColor(Color.White)
  115 + .fontWeight(600)
  116 + .margin({ bottom: 30 })
  117 + .visibility(this.isDragging ? Visibility.Visible : Visibility.None)
  118 +
  119 + Row() {
  120 + Image($r(`app.media.ic_play`)).height(24).width(24)
  121 + .visibility(this.status === PlayerConstants.STATUS_START ? Visibility.None : Visibility.Visible)
  122 + .onClick(() => {
  123 + this.playerController?.switchPlayOrPause()
  124 + })
  125 + Image($r(`app.media.ic_pause`)).height(24).width(24)
  126 + .visibility(this.status === PlayerConstants.STATUS_PAUSE ? Visibility.None : Visibility.Visible)
  127 + .onClick(() => {
  128 + this.playerController?.switchPlayOrPause()
  129 + })
  130 +
  131 + Text(DateTimeUtils.secondToTime(Math.ceil((this.progressVal / 100 * this.videoDuration))))
  132 + .fontSize(12)
  133 + .fontWeight(600)
  134 + .fontColor(Color.White)
  135 + .margin({ left: 16, right: 8 })
  136 +
  137 + PlayerProgressFullScreenView({ playerController: this.playerController }).layoutWeight(1)
  138 +
  139 + Text(DateTimeUtils.secondToTime(this.videoDuration))
  140 + .fontSize(12)
  141 + .fontWeight(600)
  142 + .fontColor(Color.White)
  143 + .margin({ left: 16 })
  144 + }
  145 + .width('100%')
  146 + .height(73)
  147 + .alignItems(VerticalAlign.Center)
  148 + .justifyContent(FlexAlign.SpaceBetween)
  149 + }
  150 + .width('100%')
  151 + .position({ x: 0, y: '100%' })
  152 + .markAnchor({ y: '100%' })
  153 + .align(Alignment.Bottom)
  154 + .padding({ left: 40, right: 40 })
  155 + .linearGradient({
  156 + direction: GradientDirection.Bottom, // 渐变方向
  157 + colors: [['rgba(0,0,0,0.5)', 0],
  158 + ['rgba(1,1,1,0)', 1.0]] // 数组末尾元素占比小于1时满足重复着色效果
  159 + })
  160 +
  161 + }
  162 +}
  1 +import { ContentDetailDTO } from 'wdBean/Index';
  2 +import { DateTimeUtils } from 'wdKit/Index';
  3 +import { PlayerConstants, WDPlayerController } from 'wdPlayer/Index';
  4 +
  5 +@Component
  6 +export struct PlayerProgressFullScreenView {
  7 + private playerController?: WDPlayerController;
  8 + @Consume contentDetailData: ContentDetailDTO
  9 + @Consume progressVal: number;
  10 + @Consume isOpenDetail: boolean
  11 + @Consume isDragging: boolean
  12 + @Consume status: number
  13 + @State videoDuration: number = this.contentDetailData?.videoInfo?.[0]?.videoDuration || 1
  14 +
  15 + aboutToAppear() {
  16 + if (this.playerController) {
  17 +
  18 + this.playerController.onSeekDone = (status: number) => {
  19 + this.playerController?.play()
  20 + }
  21 + }
  22 + }
  23 +
  24 + build() {
  25 + Column() {
  26 +
  27 + Slider({
  28 + value: this.progressVal,
  29 + step: 0.01,
  30 + // style: SliderStyle.OutSet
  31 + })
  32 + .blockColor($r('app.color.play_block_color'))
  33 + .trackColor($r('app.color.pause_track_color'))
  34 + .selectedColor($r('app.color.pause_selected_color'))
  35 + .trackThickness(4)
  36 + .blockStyle({
  37 + type: SliderBlockType.IMAGE,
  38 + image: $r('app.media.ic_player_block')
  39 + })
  40 + .blockSize({ width: 18, height: 12 })
  41 + .width('100%')
  42 + .height(19)
  43 + .onChange((value: number, mode: SliderChangeMode) => {
  44 + this.progressVal = value
  45 + if (mode === SliderChangeMode.Moving) {
  46 + this.isDragging = true
  47 + }
  48 + if (mode === SliderChangeMode.End) {
  49 + this.isDragging = false
  50 + }
  51 + this.playerController?.setSeekTime(value, mode);
  52 + console.log('slider onChange:', value, mode)
  53 +
  54 + })
  55 + }
  56 + }
  57 +}
@@ -9,7 +9,7 @@ export struct PlayerProgressView { @@ -9,7 +9,7 @@ export struct PlayerProgressView {
9 @Consume progressVal: number; 9 @Consume progressVal: number;
10 @Consume isOpenDetail: boolean 10 @Consume isOpenDetail: boolean
11 @Consume isDragging: boolean 11 @Consume isDragging: boolean
12 - @State status: number = PlayerConstants.STATUS_START; 12 + @Consume status: number
13 @State videoDuration: number = this.contentDetailData?.videoInfo?.[0]?.videoDuration || 1 13 @State videoDuration: number = this.contentDetailData?.videoInfo?.[0]?.videoDuration || 1
14 14
15 aboutToAppear() { 15 aboutToAppear() {