From 6f2e42681f3cc90b8186e97f4ae7970e2bfcc1fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=AE=B6=E7=91=9E?= <815882449@qq.com> Date: Fri, 12 Jul 2024 16:42:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E5=A4=9A=E9=95=BF=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E4=BF=AE=E6=94=B9har=E5=8C=85+navigation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +- commons/base/hvigorfile.ts | 4 +- .../base/src/main/ets/utils/AvPlayerUtil.ets | 6 +- commons/base/src/main/module.json5 | 6 +- .../main/resources/base/element/string.json | 8 - features/home/hvigorfile.ts | 4 +- .../home/src/main/ets/view/BannerView.ets | 118 ++++--- features/home/src/main/ets/view/Home.ets | 3 +- .../home/src/main/ets/view/PreviousVideo.ets | 10 +- features/home/src/main/module.json5 | 7 +- .../main/resources/base/element/string.json | 4 - features/search/hvigorfile.ts | 4 +- .../search/src/main/ets/view/SearchResult.ets | 9 +- features/search/src/main/module.json5 | 6 +- .../main/resources/base/element/string.json | 8 - features/videoDetail/Index.ets | 1 - features/videoDetail/hvigorfile.ts | 4 +- .../videoDetail/src/main/ets/pages/Index.ets | 209 ------------ .../src/main/ets/view/VideoDetail.ets | 320 +++++++++--------- .../src/main/ets/view/VideoDetailView.ets | 197 +++++++++++ features/videoDetail/src/main/module.json5 | 7 +- .../main/resources/base/element/string.json | 8 - .../resources/base/profile/main_pages.json | 5 - features/videoPlayer/Index.ets | 1 + features/videoPlayer/hvigorfile.ts | 4 +- .../{pages/Index.ets => view/VideoPlayer.ets} | 273 ++++++++------- features/videoPlayer/src/main/module.json5 | 7 +- .../main/resources/base/element/string.json | 8 - .../resources/base/profile/main_pages.json | 5 - products/phone/oh-package.json5 | 3 +- .../main/ets/entryability/EntryAbility.ets | 2 +- products/phone/src/main/ets/pages/Index.ets | 30 +- screenshots/device/config.png | Bin 37380 -> 0 bytes screenshots/device/run.png | Bin 221 -> 0 bytes 34 files changed, 614 insertions(+), 674 deletions(-) delete mode 100644 commons/base/src/main/resources/base/element/string.json delete mode 100644 features/search/src/main/resources/base/element/string.json delete mode 100644 features/videoDetail/src/main/ets/pages/Index.ets create mode 100644 features/videoDetail/src/main/ets/view/VideoDetailView.ets delete mode 100644 features/videoDetail/src/main/resources/base/element/string.json delete mode 100644 features/videoDetail/src/main/resources/base/profile/main_pages.json rename features/videoPlayer/src/main/ets/{pages/Index.ets => view/VideoPlayer.ets} (48%) delete mode 100644 features/videoPlayer/src/main/resources/base/element/string.json delete mode 100644 features/videoPlayer/src/main/resources/base/profile/main_pages.json delete mode 100644 screenshots/device/config.png delete mode 100644 screenshots/device/run.png diff --git a/README.md b/README.md index 55d4e29..dceee46 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 一多开发实例-长视频 +# 优秀实践-一多开发实例-长视频 ### 简介 @@ -46,8 +46,3 @@ 2. HarmonyOS系统:HarmonyOS NEXT Developer Beta1及以上。 3. DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。 4. HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。 - -### 注意 - -运行时需设置引用所有HSP模块。点击Run > Edit Configurations,选择Deploy Multi Hap标签页,勾选Deploy Multi Hap Packages, 选择使用方模块(phone)和所有HSP模块,点击OK。单击Run > Run “模块名称”(如Run ”entry“)或![](screenshots/device/run.png)来启动应用/服务的编译构建。 -![](screenshots/device/config.png) diff --git a/commons/base/hvigorfile.ts b/commons/base/hvigorfile.ts index d993120..4218707 100644 --- a/commons/base/hvigorfile.ts +++ b/commons/base/hvigorfile.ts @@ -1,6 +1,6 @@ -import { hspTasks } from '@ohos/hvigor-ohos-plugin'; +import { harTasks } from '@ohos/hvigor-ohos-plugin'; export default { - system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ } diff --git a/commons/base/src/main/ets/utils/AvPlayerUtil.ets b/commons/base/src/main/ets/utils/AvPlayerUtil.ets index 85280ce..c08657c 100644 --- a/commons/base/src/main/ets/utils/AvPlayerUtil.ets +++ b/commons/base/src/main/ets/utils/AvPlayerUtil.ets @@ -54,8 +54,7 @@ export class AvPlayerUtil { } switch (state) { case CommonConstants.AV_PLAYER_IDLE_STATE: - this.url = await this.context.createModuleContext(CommonConstants.VIDEO_DETAIL_HSP_NAME).resourceManager - .getRawFd(CommonConstants.PRODUCT_VIDEO_NAME); + this.url = await this.context.resourceManager.getRawFd(CommonConstants.PRODUCT_VIDEO_NAME); this.avPlayer.fdSrc = this.url; Logger.info('AVPlayer state idle called.'); break; @@ -126,8 +125,7 @@ export class AvPlayerUtil { this.surfaceId = surfaceId; Logger.info('Created AvPlayer successfully.'); // Entering idle state. - this.url = await this.context.createModuleContext(CommonConstants.VIDEO_DETAIL_HSP_NAME).resourceManager - .getRawFd(CommonConstants.PRODUCT_VIDEO_NAME); + this.url = await this.context.resourceManager.getRawFd(CommonConstants.PRODUCT_VIDEO_NAME); this.avPlayer.fdSrc = this.url; this.setAVPlayerCallback(); } else { diff --git a/commons/base/src/main/module.json5 b/commons/base/src/main/module.json5 index 74b8ece..5b88767 100644 --- a/commons/base/src/main/module.json5 +++ b/commons/base/src/main/module.json5 @@ -1,13 +1,11 @@ { "module": { "name": "base", - "type": "shared", - "description": "$string:shared_desc", + "type": "har", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true + ] } } \ No newline at end of file diff --git a/commons/base/src/main/resources/base/element/string.json b/commons/base/src/main/resources/base/element/string.json deleted file mode 100644 index 98e1d8a..0000000 --- a/commons/base/src/main/resources/base/element/string.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "string": [ - { - "name": "shared_desc", - "value": "description" - } - ] -} \ No newline at end of file diff --git a/features/home/hvigorfile.ts b/features/home/hvigorfile.ts index d993120..4218707 100644 --- a/features/home/hvigorfile.ts +++ b/features/home/hvigorfile.ts @@ -1,6 +1,6 @@ -import { hspTasks } from '@ohos/hvigor-ohos-plugin'; +import { harTasks } from '@ohos/hvigor-ohos-plugin'; export default { - system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ } diff --git a/features/home/src/main/ets/view/BannerView.ets b/features/home/src/main/ets/view/BannerView.ets index ee6a3f0..2ec304a 100644 --- a/features/home/src/main/ets/view/BannerView.ets +++ b/features/home/src/main/ets/view/BannerView.ets @@ -74,72 +74,70 @@ export struct BannerView { Row() { Swiper() { LazyForEach(this.bannerDataSource, (item: Banner, index: number) => { - Column() { - Stack() { - Image(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? item.getBannerImg().getImgSrcSm() : - item.getBannerImg().getImgSrc()) - .objectFit(ImageFit.Fill) - .borderRadius($r('app.float.banner_img_border_radius')) - .height(CommonConstants.FULL_PERCENT) - .width(CommonConstants.FULL_PERCENT) - .focusable(true) - .groupDefaultFocus(index === 0 ? true : false) - .stateStyles({ - normal: this.normalStyles, - focused: this.focusedStyles - }) + Stack() { + Image(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? item.getBannerImg().getImgSrcSm() : + item.getBannerImg().getImgSrc()) + .objectFit(ImageFit.Fill) + .borderRadius($r('app.float.banner_img_border_radius')) + .height(CommonConstants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) + .focusable(true) + .groupDefaultFocus(index === 0 ? true : false) + .stateStyles({ + normal: this.normalStyles, + focused: this.focusedStyles + }) - Column() { - Text(item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? - item.getDescription().getDescription()[0] + item.getDescription().getDescription()[1] : - item.getDescription().getDescription()[0]) - .fontSize(item.getDescription().getFontSize().getValue(this.currentBreakpoint)[0]) - .fontWeight(item.getDescription().getFontWeight()[0]) - .lineHeight(item.getDescription().getLineHeight().getValue(this.currentBreakpoint)[0]) - .fontColor(Color.White) - .letterSpacing(HomeConstants.BANNER_TEXT_LETTER_SPACES[2]) - .maxLines(1) + Column() { + Text(item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? + item.getDescription().getDescription()[0] + item.getDescription().getDescription()[1] : + item.getDescription().getDescription()[0]) + .fontSize(item.getDescription().getFontSize().getValue(this.currentBreakpoint)[0]) + .fontWeight(item.getDescription().getFontWeight()[0]) + .lineHeight(item.getDescription().getLineHeight().getValue(this.currentBreakpoint)[0]) + .fontColor(Color.White) + .letterSpacing(HomeConstants.BANNER_TEXT_LETTER_SPACES[2]) + .maxLines(1) - Text(item.getDescription().getDescription()[1]) - .fontSize(item.getDescription().getFontSize().getValue(this.currentBreakpoint)[0]) - .fontWeight(item.getDescription().getFontWeight()[0]) - .lineHeight(item.getDescription().getLineHeight().getValue(this.currentBreakpoint)[0]) - .fontColor(Color.White) - .letterSpacing(HomeConstants.BANNER_TEXT_LETTER_SPACES[2]) - .maxLines(1) - .visibility(item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? - Visibility.None : Visibility.Visible) + Text(item.getDescription().getDescription()[1]) + .fontSize(item.getDescription().getFontSize().getValue(this.currentBreakpoint)[0]) + .fontWeight(item.getDescription().getFontWeight()[0]) + .lineHeight(item.getDescription().getLineHeight().getValue(this.currentBreakpoint)[0]) + .fontColor(Color.White) + .letterSpacing(HomeConstants.BANNER_TEXT_LETTER_SPACES[2]) + .maxLines(1) + .visibility(item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? + Visibility.None : Visibility.Visible) - Text(item.getDescription().getDescription()[2]) - .fontSize(item.getDescription().getFontSize().getValue(this.currentBreakpoint)[1]) - .fontWeight(item.getDescription().getFontWeight()[1]) - .lineHeight(item.getDescription().getLineHeight().getValue(this.currentBreakpoint)[1]) - .fontColor(Color.White) - .margin({ - top: item.getDescription().getTopPosition().getValue(this.currentBreakpoint)[1] - }) - .letterSpacing(HomeConstants.BANNER_TEXT_LETTER_SPACES[1]) - .maxLines(1) - } - .padding({ - left: !item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? - item.getDescription().getLeftPosition().getValue(this.currentBreakpoint)[0] : '0', - top: !item.getDescription().getIsTopCenter().getValue(this.currentBreakpoint) ? - item.getDescription().getTopPosition().getValue(this.currentBreakpoint)[0] : '0' - }) - .alignItems(item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? - HorizontalAlign.Center : HorizontalAlign.Start) - .justifyContent(!item.getDescription().getIsTopCenter().getValue(this.currentBreakpoint) ? - FlexAlign.Start : FlexAlign.Center) - .height(CommonConstants.FULL_PERCENT) - .width(CommonConstants.FULL_PERCENT) + Text(item.getDescription().getDescription()[2]) + .fontSize(item.getDescription().getFontSize().getValue(this.currentBreakpoint)[1]) + .fontWeight(item.getDescription().getFontWeight()[1]) + .lineHeight(item.getDescription().getLineHeight().getValue(this.currentBreakpoint)[1]) + .fontColor(Color.White) + .margin({ + top: item.getDescription().getTopPosition().getValue(this.currentBreakpoint)[1] + }) + .letterSpacing(HomeConstants.BANNER_TEXT_LETTER_SPACES[1]) + .maxLines(1) } - .height(item.getBannerImg().getHeight().getValue(this.currentBreakpoint)) + .padding({ + left: !item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? + item.getDescription().getLeftPosition().getValue(this.currentBreakpoint)[0] : '0', + top: !item.getDescription().getIsTopCenter().getValue(this.currentBreakpoint) ? + item.getDescription().getTopPosition().getValue(this.currentBreakpoint)[0] : '0' + }) + .alignItems(item.getDescription().getIsLeftCenter().getValue(this.currentBreakpoint) ? + HorizontalAlign.Center : HorizontalAlign.Start) + .justifyContent(!item.getDescription().getIsTopCenter().getValue(this.currentBreakpoint) ? + FlexAlign.Start : FlexAlign.Center) + .height(CommonConstants.FULL_PERCENT) .width(CommonConstants.FULL_PERCENT) - // The width and height vary with the container assembly and the aspect ratio remains unchanged. - .aspectRatio(new BreakpointType(HomeConstants.BANNER_RATIOS[0], HomeConstants.BANNER_RATIOS[1], - HomeConstants.BANNER_RATIOS[2]).getValue(this.currentBreakpoint)) } + .height(item.getBannerImg().getHeight().getValue(this.currentBreakpoint)) + .width(CommonConstants.FULL_PERCENT) + // The width and height vary with the container assembly and the aspect ratio remains unchanged. + .aspectRatio(new BreakpointType(HomeConstants.BANNER_RATIOS[0], HomeConstants.BANNER_RATIOS[1], + HomeConstants.BANNER_RATIOS[2]).getValue(this.currentBreakpoint)) }, (item: Banner, index: number) => index + JSON.stringify(item)) } .tabIndex(getTabIndex(HomeConstants.DIRECTION_LIST[2])) diff --git a/features/home/src/main/ets/view/Home.ets b/features/home/src/main/ets/view/Home.ets index 93033bb..547fe41 100644 --- a/features/home/src/main/ets/view/Home.ets +++ b/features/home/src/main/ets/view/Home.ets @@ -75,8 +75,9 @@ export struct Home { .scrollBar(BarState.Off) .height(CommonConstants.FULL_PERCENT) // Obtains the sliding offset on the y axis during sliding. - .onScroll(() => { + .onScrollFrameBegin((offset: number) => { this.scrollHeight = this.sideScroller.currentOffset().yOffset; + return { offsetRemain: offset } }) HomeHeader({ isSearching: $isSearching }) diff --git a/features/home/src/main/ets/view/PreviousVideo.ets b/features/home/src/main/ets/view/PreviousVideo.ets index 3390c5d..76436d6 100644 --- a/features/home/src/main/ets/view/PreviousVideo.ets +++ b/features/home/src/main/ets/view/PreviousVideo.ets @@ -15,7 +15,6 @@ import { BreakpointConstants, CommonConstants } from '@ohos/commons'; import { BreakpointType } from '@ohos/commons'; -import { router } from '@kit.ArkUI'; import { HomeConstants } from '../constants/HomeConstants'; import { VideoImage, VideoImgViewModel } from '../viewmodel/VideoImgViewModel'; import { PreviousVideoUtil } from '../utils/PreviousVideoUtil'; @@ -26,6 +25,7 @@ export struct PreviousVideo { @StorageLink('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_LG; @StorageLink('currentTopIndex') currentTopIndex: number = 0; @State previousVideoImgListTwo: VideoImage[] = new VideoImgViewModel().getPreviousVideoTwo(this.currentBreakpoint); + @Consume('pageInfo') pageInfo: NavPathStack; private previousVideoImgListOne: VideoImage[] = new VideoImgViewModel().getPreviousVideoOne(); @Styles focusedStyles(): void { @@ -116,13 +116,7 @@ export struct PreviousVideo { .layoutWeight(1) .groupDefaultFocus(index === 0 ? true : false) .onClick(() => { - router.pushUrl({ - url: HomeConstants.VIDEO_DETAIL_URL, - params: { - currentTime: 0, - isLayoutFullScreen: this.currentTopIndex === 2 ? true : false - } - }) + this.pageInfo.pushPath({ name: 'VideoDetail' }); }) Blank() diff --git a/features/home/src/main/module.json5 b/features/home/src/main/module.json5 index 2c96c8a..7a40a43 100644 --- a/features/home/src/main/module.json5 +++ b/features/home/src/main/module.json5 @@ -1,14 +1,11 @@ { "module": { "name": "home", - "type": "shared", - "description": "$string:shared_desc", + "type": "har", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true, - "pages": "$profile:main_pages" + ] } } \ No newline at end of file diff --git a/features/home/src/main/resources/base/element/string.json b/features/home/src/main/resources/base/element/string.json index 11e582e..51850af 100644 --- a/features/home/src/main/resources/base/element/string.json +++ b/features/home/src/main/resources/base/element/string.json @@ -1,9 +1,5 @@ { "string": [ - { - "name": "shared_desc", - "value": "description" - }, { "name": "tab_home", "value": "首页" diff --git a/features/search/hvigorfile.ts b/features/search/hvigorfile.ts index d993120..4218707 100644 --- a/features/search/hvigorfile.ts +++ b/features/search/hvigorfile.ts @@ -1,6 +1,6 @@ -import { hspTasks } from '@ohos/hvigor-ohos-plugin'; +import { harTasks } from '@ohos/hvigor-ohos-plugin'; export default { - system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ } diff --git a/features/search/src/main/ets/view/SearchResult.ets b/features/search/src/main/ets/view/SearchResult.ets index f80c22a..d24b77f 100644 --- a/features/search/src/main/ets/view/SearchResult.ets +++ b/features/search/src/main/ets/view/SearchResult.ets @@ -15,7 +15,6 @@ import { BreakpointConstants, CommonConstants } from '@ohos/commons'; import { BreakpointType } from '@ohos/commons'; -import { router } from '@kit.ArkUI'; import { SearchConstants } from '../constants/SearchConstants'; import { SearchVideoImg, SearchVideoImgModel } from '../viewmodel/SearchVideoImgViewModel'; @@ -23,6 +22,7 @@ import { SearchVideoImg, SearchVideoImgModel } from '../viewmodel/SearchVideoImg export struct SearchResult { @StorageLink('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_LG; @State resultTabIndex: number = 0; + @Consume('pageInfo') pageInfo: NavPathStack; build() { Scroll() { @@ -163,12 +163,7 @@ export struct SearchResult { .fontColor(Color.White) .layoutWeight(1) .onClick(() => { - router.pushUrl({ - url: SearchConstants.VIDEO_DETAIL_URL, - params: { - currentTime: 0 - } - }) + this.pageInfo.pushPath({ name: 'VideoDetail' }); }) Blank() diff --git a/features/search/src/main/module.json5 b/features/search/src/main/module.json5 index 6924576..c3b61da 100644 --- a/features/search/src/main/module.json5 +++ b/features/search/src/main/module.json5 @@ -1,13 +1,11 @@ { "module": { "name": "search", - "type": "shared", - "description": "$string:shared_desc", + "type": "har", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true + ] } } \ No newline at end of file diff --git a/features/search/src/main/resources/base/element/string.json b/features/search/src/main/resources/base/element/string.json deleted file mode 100644 index 98e1d8a..0000000 --- a/features/search/src/main/resources/base/element/string.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "string": [ - { - "name": "shared_desc", - "value": "description" - } - ] -} \ No newline at end of file diff --git a/features/videoDetail/Index.ets b/features/videoDetail/Index.ets index 664fba0..e69de29 100644 --- a/features/videoDetail/Index.ets +++ b/features/videoDetail/Index.ets @@ -1 +0,0 @@ -export { FoldStateParam } from './src/main/ets/pages/Index'; diff --git a/features/videoDetail/hvigorfile.ts b/features/videoDetail/hvigorfile.ts index d993120..4218707 100644 --- a/features/videoDetail/hvigorfile.ts +++ b/features/videoDetail/hvigorfile.ts @@ -1,6 +1,6 @@ -import { hspTasks } from '@ohos/hvigor-ohos-plugin'; +import { harTasks } from '@ohos/hvigor-ohos-plugin'; export default { - system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ } diff --git a/features/videoDetail/src/main/ets/pages/Index.ets b/features/videoDetail/src/main/ets/pages/Index.ets deleted file mode 100644 index bdc3b8b..0000000 --- a/features/videoDetail/src/main/ets/pages/Index.ets +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Callback } from '@kit.BasicServicesKit'; -import { AvPlayerUtil, DeviceScreen, Logger, WindowUtil, BreakpointConstants, CommonConstants, DisplayUtil } from - '@ohos/commons'; -import { display, router, window } from '@kit.ArkUI'; -import { SelfComment } from '../view/SelfComment'; -import { AllComments } from '../view/AllComments'; -import { VideoDetail } from '../view/VideoDetail'; -import { DetailConstants } from '../constants/DetailConstants'; - -@Entry -@Component -export struct Index { - @StorageLink('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_LG; - @StorageLink('windowWidth') windowWidth: number = 0; - @StorageLink('updateTime') updateTime: number = 0; - @State commentImgHeight: string = DetailConstants.INITIAL_COMMENT_IMAGE_HEIGHT; - @State commentImgWidth: string = DetailConstants.INITIAL_COMMENT_IMAGE_WIDTH; - @State relatedVideoHeight: number = DetailConstants.INITIAL_RELATED_VIDEO_HEIGHT; - @State videoHeight: number = DetailConstants.INITIAL_VIDEO_HEIGHT; - @State screenWidth: number = DeviceScreen.getDeviceWidth(); - @State isHalfFolded: boolean = false; - private avPlayerUtil: AvPlayerUtil= new AvPlayerUtil(); - private screenHeight: number = 0; - private windowUtil?: WindowUtil; - private onDetailFoldStatusChange: Callback = (data: display.FoldStatus) => { - if (data === display.FoldStatus.FOLD_STATUS_FOLDED) { - if (this.windowUtil === undefined) { - return; - } - this.isHalfFolded = false; - this.windowUtil.setMainWindowOrientation(window.Orientation.PORTRAIT); - } else { - if (this.windowUtil === undefined) { - return; - } - this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_RESTRICTED); - if (data === display.FoldStatus.FOLD_STATUS_HALF_FOLDED) { - this.isHalfFolded = true; - // Full-screen playback. - router.pushUrl({ - url: DetailConstants.FULL_SCREEN_URL, - params: new FoldStateParam(this.isHalfFolded) - }); - } else { - this.isHalfFolded = false; - } - } - }; - - aboutToAppear() { - DisplayUtil.getFoldCreaseRegion(); - this.screenHeight = DeviceScreen.getDeviceHeight(); - this.windowUtil = WindowUtil.getInstance(); - - if (this.windowUtil === undefined) { - return; - } - if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && display.isFoldable()) { - this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_RESTRICTED); - } - } - - aboutToDisappear() { - this.updateTime = 0; - if (this.windowUtil === undefined) { - return; - } - if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && display.isFoldable()) { - this.windowUtil.setMainWindowOrientation(window.Orientation.PORTRAIT); - } - this.avPlayerUtil.release(); - } - - onPageShow() { - try { - display.on('foldStatusChange', this.onDetailFoldStatusChange); - } catch (exception) { - Logger.error('Failed to register callback. Code: ' + JSON.stringify(exception)); - } - if (this.windowUtil === undefined) { - return; - } - if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && display.isFoldable()) { - this.isHalfFolded = false; - } - this.avPlayerUtil.setStartTime(this.updateTime); - this.avPlayerUtil.playerStateControl(); - this.avPlayerUtil.onTimeUpdate(); - } - - onPageHide() { - try { - display.off('foldStatusChange'); - } catch (exception) { - Logger.error('Failed to unregister callback. Code: ' + JSON.stringify(exception)); - } - this.avPlayerUtil.pause(); - this.avPlayerUtil.offTimeUpdate(); - } - - build() { - GridRow({ - columns: { - sm: BreakpointConstants.GRID_ROW_COLUMNS[2], - md: BreakpointConstants.GRID_ROW_COLUMNS[0], - lg: BreakpointConstants.GRID_ROW_COLUMNS[0] - } - }) { - GridCol({ - span: { - sm: BreakpointConstants.GRID_COLUMN_SPANS[5], - md: BreakpointConstants.GRID_COLUMN_SPANS[0], - lg: BreakpointConstants.GRID_COLUMN_SPANS[0] - } - }) { - SideBarContainer() { - Column() { - Scroll() { - AllComments({ commentImgHeight: $commentImgHeight, commentImgWidth: $commentImgWidth }) - .visibility(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? Visibility.Visible : - Visibility.None) - } - .align(Alignment.Top) - .scrollBar(BarState.Off) - .layoutWeight(1) - .width(CommonConstants.FULL_PERCENT) - .padding({ bottom: $r('app.float.side_scroll_padding') }) - - SelfComment() - .visibility(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? Visibility.Visible : - Visibility.None) - } - .justifyContent(FlexAlign.Start) - .height(CommonConstants.FULL_PERCENT) - .width(CommonConstants.FULL_PERCENT) - .backgroundColor(Color.White) - .onAreaChange((newValue: Area) => { - if (newValue.width !== 0) { - let height: number = DetailConstants.COMMENT_IMAGE_MIN_HEIGHT_NUMBER + (Number(newValue.width) - - DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) / (this.windowWidth * DetailConstants.COMMENTS_AREA_PERCENT - - DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) * (DetailConstants.COMMENT_IMAGE_MAX_HEIGHT_NUMBER - - DetailConstants.COMMENT_IMAGE_MIN_HEIGHT_NUMBER); - let width: number = DetailConstants.COMMENT_IMAGE_MIN_WIDTH_NUMBER + (Number(newValue.width) - - DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) / (this.windowWidth * DetailConstants.COMMENTS_AREA_PERCENT - - DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) * (DetailConstants.COMMENT_IMAGE_MAX_WIDTH_NUMBER - - DetailConstants.COMMENT_IMAGE_MIN_WIDTH_NUMBER); - this.commentImgHeight = JSON.stringify(height); - this.commentImgWidth = JSON.stringify(width); - } - }) - - Column() { - VideoDetail({ screenHeight: this.screenHeight, avPlayerUtil: this.avPlayerUtil, relatedVideoHeight: - $relatedVideoHeight, videoHeight: $videoHeight, isHalfFolded: $isHalfFolded }) - .layoutWeight(1) - SelfComment() - .visibility(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? Visibility.None : - Visibility.Visible) - } - .height(CommonConstants.FULL_PERCENT) - .width(CommonConstants.FULL_PERCENT) - } - .showSideBar(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? true : false) - .showControlButton(false) - .autoHide(false) - .sideBarPosition(SideBarPosition.End) - .sideBarWidth($r('app.float.side_bar_min_width')) - .minSideBarWidth($r('app.float.side_bar_min_width')) - .maxSideBarWidth(px2vp(this.windowWidth * DetailConstants.COMMENTS_AREA_PERCENT)) - } - .height(CommonConstants.FULL_PERCENT) - } - .width(CommonConstants.FULL_PERCENT) - .height(CommonConstants.FULL_PERCENT) - .onBreakpointChange((breakPoints) => { - if (breakPoints !== BreakpointConstants.BREAKPOINT_LG && this.videoHeight < DetailConstants.INITIAL_VIDEO_HEIGHT) - { - this.relatedVideoHeight = 0; - } else if (breakPoints === BreakpointConstants.BREAKPOINT_LG) { - this.relatedVideoHeight = DetailConstants.INITIAL_RELATED_VIDEO_HEIGHT; - } else { - Logger.info(`No specific function`); - } - }) - } -} - -export class FoldStateParam { - isHalfFolded: boolean; - - constructor(isHalfFolded: boolean) { - this.isHalfFolded = isHalfFolded; - } -} \ No newline at end of file diff --git a/features/videoDetail/src/main/ets/view/VideoDetail.ets b/features/videoDetail/src/main/ets/view/VideoDetail.ets index 40ca4f5..6a120cd 100644 --- a/features/videoDetail/src/main/ets/view/VideoDetail.ets +++ b/features/videoDetail/src/main/ets/view/VideoDetail.ets @@ -13,187 +13,191 @@ * limitations under the License. */ -import { BreakpointConstants, CommonConstants } from '@ohos/commons'; -import { AvPlayerUtil, Logger } from '@ohos/commons'; -import { router } from '@kit.ArkUI'; -import { RelatedList } from './RelatedList'; -import { CurrentOffsetUtil } from '../utils/CurrentOffsetUtil'; +import { Callback } from '@kit.BasicServicesKit'; +import { display, window } from '@kit.ArkUI'; +import { AvPlayerUtil, DeviceScreen, Logger, WindowUtil, BreakpointConstants, CommonConstants, DisplayUtil } from '@ohos/commons'; +import { SelfComment } from './SelfComment'; +import { AllComments } from './AllComments'; +import { VideoDetailView } from './VideoDetailView'; import { DetailConstants } from '../constants/DetailConstants'; -import { FoldStateParam } from '../pages/Index'; @Component export struct VideoDetail { - @StorageLink('currentTime') currentTime: string = CommonConstants.INITIAL_TIME; - @StorageLink('totalTime') totalTime: string = CommonConstants.INITIAL_TIME; - @StorageLink('progress') progress: number = 0; @StorageLink('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_LG; - @Link relatedVideoHeight: number; - @Link videoHeight: number; - @Link isHalfFolded: boolean; - private avPlayerUtil: AvPlayerUtil = new AvPlayerUtil(); + @StorageLink('windowWidth') windowWidth: number = 0; + @StorageLink('updateTime') updateTime: number = 0; + @StorageLink('isHalfFolded') isHalfFolded: boolean = false; + @Consume('pageInfo') pageInfo: NavPathStack; + @State commentImgHeight: string = DetailConstants.INITIAL_COMMENT_IMAGE_HEIGHT; + @State commentImgWidth: string = DetailConstants.INITIAL_COMMENT_IMAGE_WIDTH; + @State relatedVideoHeight: number = DetailConstants.INITIAL_RELATED_VIDEO_HEIGHT; + @State videoHeight: number = DetailConstants.INITIAL_VIDEO_HEIGHT; + @State screenWidth: number = DeviceScreen.getDeviceWidth(); + private avPlayerUtil: AvPlayerUtil= new AvPlayerUtil(); private screenHeight: number = 0; - private surfaceId: string = ''; - private xComponentController: XComponentController = new XComponentController(); - private scroller: Scroller = new Scroller(); + private windowUtil?: WindowUtil; + private onDetailFoldStatusChange: Callback = (data: display.FoldStatus) => { + if (data === display.FoldStatus.FOLD_STATUS_FOLDED) { + if (this.windowUtil === undefined) { + return; + } + this.isHalfFolded = false; + this.windowUtil.setMainWindowOrientation(window.Orientation.PORTRAIT); + } else { + if (this.windowUtil === undefined) { + return; + } + this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_RESTRICTED); + if (data === display.FoldStatus.FOLD_STATUS_HALF_FOLDED) { + this.isHalfFolded = true; + // Full-screen playback. + this.pageInfo.pushPath({ name: 'VideoPlayer' }); + } else { + this.isHalfFolded = false; + } + } + }; - build() { - Scroll(this.scroller) { - Column() { - Column() { - Stack({ alignContent: Alignment.Bottom }) { - XComponent({ - id: DetailConstants.VIDEO_DETAIL, - type: XComponentType.SURFACE, - controller: this.xComponentController - }) - .onLoad(() => { - this.xComponentController.setXComponentSurfaceSize({ - surfaceWidth: CommonConstants.X_COMPONENT_SURFACE_WIDTH, - surfaceHeight: CommonConstants.X_COMPONENT_SURFACE_HEIGHT - }); - this.surfaceId = this.xComponentController.getXComponentSurfaceId(); - this.avPlayerUtil.createAvPlayer(this.surfaceId, false); - }) - .width(this.videoHeight + DetailConstants.PERCENT_SIGN) - .height(CommonConstants.FULL_PERCENT) - .aspectRatio(CommonConstants.VIDEO_ASPECT_RATIO) + aboutToAppear() { + DisplayUtil.getFoldCreaseRegion(); + this.screenHeight = DeviceScreen.getDeviceHeight(); + this.windowUtil = WindowUtil.getInstance(); - Row() { - TimeText({ time: $currentTime }) - .margin({ - left: $r('app.float.current_time_text_left'), - right: $r('app.float.current_time_text_right') - }) + if (this.windowUtil === undefined) { + return; + } + if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && display.isFoldable()) { + this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_RESTRICTED); + } + } - Slider({ min: 0, max: CommonConstants.PROGRESS_HUNDRED, step: 1, value: this.progress }) - .onChange((value: number, mode: SliderChangeMode) => { - this.avPlayerUtil.sliderChange(value, mode); - }) - .layoutWeight(1) - .selectedColor($r('app.color.episodes_font')) + aboutToDisappear() { + this.updateTime = 0; + if (this.windowUtil === undefined) { + return; + } + if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && display.isFoldable()) { + this.windowUtil.setMainWindowOrientation(window.Orientation.PORTRAIT); + } + this.avPlayerUtil.release(); + } - TimeText({ time: $totalTime }) - .margin({ - left: $r('app.float.total_time_text_left'), - right: $r('app.float.total_time_text_right') - }) + build() { + NavDestination() { + GridRow({ + columns: { + sm: BreakpointConstants.GRID_ROW_COLUMNS[2], + md: BreakpointConstants.GRID_ROW_COLUMNS[0], + lg: BreakpointConstants.GRID_ROW_COLUMNS[0] + } + }) { + GridCol({ + span: { + sm: BreakpointConstants.GRID_COLUMN_SPANS[5], + md: BreakpointConstants.GRID_COLUMN_SPANS[0], + lg: BreakpointConstants.GRID_COLUMN_SPANS[0] + } + }) { + SideBarContainer() { + Column() { + Scroll() { + AllComments({ commentImgHeight: $commentImgHeight, commentImgWidth: $commentImgWidth }) + .visibility(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? Visibility.Visible : + Visibility.None) + } + .align(Alignment.Top) + .scrollBar(BarState.Off) + .layoutWeight(1) + .width(CommonConstants.FULL_PERCENT) + .padding({ bottom: $r('app.float.side_scroll_padding') }) - Image($r('app.media.ic_public_enlarge')) - .height($r('app.float.enlarge_size')) - .width($r('app.float.enlarge_size')) - .margin({ right: $r('app.float.enlarge_margin') }) - .fillColor(Color.White) - .onClick(() => { - // Full-screen playback. - router.pushUrl({ - url: DetailConstants.FULL_SCREEN_URL, - params: new FoldStateParam(this.isHalfFolded) - }); - }) + SelfComment() + .visibility(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? Visibility.Visible : + Visibility.None) } + .justifyContent(FlexAlign.Start) + .height(CommonConstants.FULL_PERCENT) .width(CommonConstants.FULL_PERCENT) - .height($r('app.float.time_row_height')) - .alignItems(VerticalAlign.Center) + .backgroundColor(Color.White) + .onAreaChange((newValue: Area) => { + if (newValue.width !== 0) { + let height: number = DetailConstants.COMMENT_IMAGE_MIN_HEIGHT_NUMBER + (Number(newValue.width) - + DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) / (this.windowWidth * DetailConstants.COMMENTS_AREA_PERCENT - + DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) * (DetailConstants.COMMENT_IMAGE_MAX_HEIGHT_NUMBER - + DetailConstants.COMMENT_IMAGE_MIN_HEIGHT_NUMBER); + let width: number = DetailConstants.COMMENT_IMAGE_MIN_WIDTH_NUMBER + (Number(newValue.width) - + DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) / (this.windowWidth * DetailConstants.COMMENTS_AREA_PERCENT - + DetailConstants.SIDE_BAR_MIN_WIDTH_NUMBER) * (DetailConstants.COMMENT_IMAGE_MAX_WIDTH_NUMBER - + DetailConstants.COMMENT_IMAGE_MIN_WIDTH_NUMBER); + this.commentImgHeight = JSON.stringify(height); + this.commentImgWidth = JSON.stringify(width); + } + }) - Image($r('app.media.ic_public_back')) - .height($r('app.float.back_size')) - .width($r('app.float.back_size')) - .position({ - x: $r('app.float.back_position_x'), - y: $r('app.float.back_position_y') - }) - .fillColor(Color.White) - .onClick(() => { - router.back(); + Column() { + VideoDetailView({ + screenHeight: this.screenHeight, + avPlayerUtil: this.avPlayerUtil, + relatedVideoHeight: + $relatedVideoHeight, + videoHeight: $videoHeight }) + .layoutWeight(1) + SelfComment() + .visibility(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? Visibility.None : + Visibility.Visible) + } + .height(CommonConstants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) } - .width(CommonConstants.FULL_PERCENT) - .backgroundColor(Color.Black) - .onClick(() => { - this.avPlayerUtil.playerStateControl(); - }) - - RelatedList({ relatedVideoHeight: $relatedVideoHeight, videoHeight: $videoHeight, screenHeight: - this.screenHeight }) + .showSideBar(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? true : false) + .showControlButton(false) + .autoHide(false) + .sideBarPosition(SideBarPosition.End) + .sideBarWidth($r('app.float.side_bar_min_width')) + .minSideBarWidth($r('app.float.side_bar_min_width')) + .maxSideBarWidth(px2vp(this.windowWidth * DetailConstants.COMMENTS_AREA_PERCENT)) } - .justifyContent(FlexAlign.Start) + .height(CommonConstants.FULL_PERCENT) } .width(CommonConstants.FULL_PERCENT) - .padding({ bottom: $r('app.float.video_col_padding') }) - } - .scrollable(ScrollDirection.Vertical) - .scrollBar(BarState.Off) - .height(CommonConstants.FULL_PERCENT) - .onScrollFrameBegin((offset: number) => { - if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG) { - if ((offset > 0) && (this.videoHeight > DetailConstants.MIN_VIDEO_PERCENT)) { - // Video zoom-out logic. - // Percentage of screen height by sliding. - let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; - // Video shrinkage percentage. - let heightOffset = offsetPercent < this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT ? offsetPercent : - this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT; - this.videoHeight = this.videoHeight - heightOffset; - } else if ((offset < 0) && (this.videoHeight < DetailConstants.MAX_VIDEO_PERCENT) && - (CurrentOffsetUtil.scrollToTop(JSON.stringify(this.scroller.currentOffset())))) { - // Video magnification logic. - let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; - let heightOffset = offsetPercent < DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight ? offsetPercent : - DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight; - this.videoHeight = this.videoHeight + heightOffset; - } else { - Logger.info(`No specific function`); - } - } else { - if ((offset > 0) && (this.videoHeight === DetailConstants.MAX_VIDEO_PERCENT) && (this.relatedVideoHeight > 0)) { - // Related list shrinking logic. - // Percentage of screen height by sliding. - let offsetPercent = (Math.abs(offset) * DetailConstants.TEN) / this.screenHeight; - this.relatedVideoHeight = (this.relatedVideoHeight - offsetPercent * DetailConstants.RELATED_LIST_HEIGHT) < - 0 ? 0 : (this.relatedVideoHeight - offsetPercent * DetailConstants.RELATED_LIST_HEIGHT); - } else if ((offset > 0) && (this.videoHeight > DetailConstants.MIN_VIDEO_PERCENT) && - (this.relatedVideoHeight === 0)) { - // Video zoom-out logic. - // Percentage of screen height by sliding. - let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; - // Video shrinkage percentage. - let heightOffset = offsetPercent < this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT ? offsetPercent : - this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT; - this.videoHeight = this.videoHeight - heightOffset; - } else if ((this.videoHeight < DetailConstants.MAX_VIDEO_PERCENT) && (this.relatedVideoHeight === 0) - && (offset < 0) && (CurrentOffsetUtil.scrollToTop(JSON.stringify(this.scroller.currentOffset())))) { - // Video magnification logic. - let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; - let heightOffset = offsetPercent < DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight ? offsetPercent : - DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight; - this.videoHeight = this.videoHeight + heightOffset; - } else if ((offset < 0) && (this.videoHeight === DetailConstants.MAX_VIDEO_PERCENT) && - (this.relatedVideoHeight >= 0)) { - // Related list enlargement logic. - // Percentage of screen height by sliding. - let offsetPercent = (Math.abs(offset) * DetailConstants.TEN) / this.screenHeight; - this.relatedVideoHeight = (this.relatedVideoHeight + offsetPercent * DetailConstants.RELATED_LIST_HEIGHT) > - DetailConstants.RELATED_LIST_HEIGHT ? DetailConstants.RELATED_LIST_HEIGHT : (this.relatedVideoHeight + - offsetPercent * DetailConstants.RELATED_LIST_HEIGHT); + .height(CommonConstants.FULL_PERCENT) + .onBreakpointChange((breakPoints) => { + if (breakPoints !== BreakpointConstants.BREAKPOINT_LG && + this.videoHeight < DetailConstants.INITIAL_VIDEO_HEIGHT) { + this.relatedVideoHeight = 0; + } else if (breakPoints === BreakpointConstants.BREAKPOINT_LG) { + this.relatedVideoHeight = DetailConstants.INITIAL_RELATED_VIDEO_HEIGHT; } else { Logger.info(`No specific function`); } + }) + } + .hideTitleBar(true) + .onShown(() => { + try { + display.on('foldStatusChange', this.onDetailFoldStatusChange); + } catch (exception) { + Logger.error('Failed to register callback. Code: ' + JSON.stringify(exception)); } - // Returns the actual offset 0. - return { offsetRemain: 0 }; + if (this.windowUtil === undefined) { + return; + } + if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && display.isFoldable()) { + this.isHalfFolded = false; + } + this.avPlayerUtil.setStartTime(this.updateTime); + this.avPlayerUtil.playerStateControl(); + this.avPlayerUtil.onTimeUpdate(); + }) + .onHidden(() => { + try { + display.off('foldStatusChange'); + } catch (exception) { + Logger.error('Failed to unregister callback. Code: ' + JSON.stringify(exception)); + } + this.avPlayerUtil.pause(); + this.avPlayerUtil.offTimeUpdate(); }) - } -} - -@Component -struct TimeText { - @Link time: string; - - build() { - Text(this.time) - .fontSize($r('app.float.time_font')) - .fontColor(Color.White) - .lineHeight($r('app.float.time_text_line')) - .width($r('app.float.time_text_width')) } } \ No newline at end of file diff --git a/features/videoDetail/src/main/ets/view/VideoDetailView.ets b/features/videoDetail/src/main/ets/view/VideoDetailView.ets new file mode 100644 index 0000000..81c601f --- /dev/null +++ b/features/videoDetail/src/main/ets/view/VideoDetailView.ets @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BreakpointConstants, CommonConstants } from '@ohos/commons'; +import { AvPlayerUtil, Logger } from '@ohos/commons'; +import { RelatedList } from './RelatedList'; +import { CurrentOffsetUtil } from '../utils/CurrentOffsetUtil'; +import { DetailConstants } from '../constants/DetailConstants'; + +@Component +export struct VideoDetailView { + @StorageLink('currentTime') currentTime: string = CommonConstants.INITIAL_TIME; + @StorageLink('totalTime') totalTime: string = CommonConstants.INITIAL_TIME; + @StorageLink('progress') progress: number = 0; + @StorageLink('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_LG; + @StorageLink('isHalfFolded') isHalfFolded: boolean = false; + @Consume('pageInfo') pageInfo: NavPathStack; + @Link relatedVideoHeight: number; + @Link videoHeight: number; + private avPlayerUtil: AvPlayerUtil = new AvPlayerUtil(); + private screenHeight: number = 0; + private surfaceId: string = ''; + private xComponentController: XComponentController = new XComponentController(); + private scroller: Scroller = new Scroller(); + + build() { + Scroll(this.scroller) { + Column() { + Stack({ alignContent: Alignment.Bottom }) { + XComponent({ + id: DetailConstants.VIDEO_DETAIL, + type: XComponentType.SURFACE, + controller: this.xComponentController + }) + .onLoad(() => { + this.surfaceId = this.xComponentController.getXComponentSurfaceId(); + this.avPlayerUtil.createAvPlayer(this.surfaceId, false); + }) + .width(this.videoHeight + DetailConstants.PERCENT_SIGN) + .height(CommonConstants.FULL_PERCENT) + .aspectRatio(CommonConstants.VIDEO_ASPECT_RATIO) + + Row() { + TimeText({ time: $currentTime }) + .margin({ + left: $r('app.float.current_time_text_left'), + right: $r('app.float.current_time_text_right') + }) + + Slider({ + min: 0, + max: CommonConstants.PROGRESS_HUNDRED, + step: 1, + value: this.progress + }) + .onChange((value: number, mode: SliderChangeMode) => { + this.avPlayerUtil.sliderChange(value, mode); + }) + .layoutWeight(1) + .selectedColor($r('app.color.episodes_font')) + + TimeText({ time: $totalTime }) + .margin({ + left: $r('app.float.total_time_text_left'), + right: $r('app.float.total_time_text_right') + }) + + Image($r('app.media.ic_public_enlarge')) + .height($r('app.float.enlarge_size')) + .width($r('app.float.enlarge_size')) + .margin({ right: $r('app.float.enlarge_margin') }) + .fillColor(Color.White) + .onClick(() => { + // Full-screen playback. + this.pageInfo.pushPath({ name: 'VideoPlayer' }); + }) + } + .width(CommonConstants.FULL_PERCENT) + .height($r('app.float.time_row_height')) + .alignItems(VerticalAlign.Center) + + Image($r('app.media.ic_public_back')) + .height($r('app.float.back_size')) + .width($r('app.float.back_size')) + .position({ + x: $r('app.float.back_position_x'), + y: $r('app.float.back_position_y') + }) + .fillColor(Color.White) + .onClick(() => { + this.pageInfo.pop(); + }) + } + .width(CommonConstants.FULL_PERCENT) + .backgroundColor(Color.Black) + .onClick(() => { + this.avPlayerUtil.playerStateControl(); + }) + + RelatedList({ + relatedVideoHeight: $relatedVideoHeight, + videoHeight: $videoHeight, + screenHeight: this.screenHeight + }) + } + .width(CommonConstants.FULL_PERCENT) + .justifyContent(FlexAlign.Start) + .padding({ bottom: $r('app.float.video_col_padding') }) + } + .scrollable(ScrollDirection.Vertical) + .scrollBar(BarState.Off) + .height(CommonConstants.FULL_PERCENT) + .onScrollFrameBegin((offset: number) => { + if (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG) { + if ((offset > 0) && (this.videoHeight > DetailConstants.MIN_VIDEO_PERCENT)) { + // Video zoom-out logic. + // Percentage of screen height by sliding. + let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; + // Video shrinkage percentage. + let heightOffset = offsetPercent < this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT ? offsetPercent : + this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT; + this.videoHeight = this.videoHeight - heightOffset; + } else if ((offset < 0) && (this.videoHeight < DetailConstants.MAX_VIDEO_PERCENT) && + (CurrentOffsetUtil.scrollToTop(JSON.stringify(this.scroller.currentOffset())))) { + // Video magnification logic. + let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; + let heightOffset = offsetPercent < DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight ? offsetPercent : + DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight; + this.videoHeight = this.videoHeight + heightOffset; + } else { + Logger.info(`No specific function`); + } + } else { + if ((offset > 0) && (this.videoHeight === DetailConstants.MAX_VIDEO_PERCENT) && (this.relatedVideoHeight > 0)) { + // Related list shrinking logic. + // Percentage of screen height by sliding. + let offsetPercent = (Math.abs(offset) * DetailConstants.TEN) / this.screenHeight; + this.relatedVideoHeight = (this.relatedVideoHeight - offsetPercent * DetailConstants.RELATED_LIST_HEIGHT) < + 0 ? 0 : (this.relatedVideoHeight - offsetPercent * DetailConstants.RELATED_LIST_HEIGHT); + } else if ((offset > 0) && (this.videoHeight > DetailConstants.MIN_VIDEO_PERCENT) && + (this.relatedVideoHeight === 0)) { + // Video zoom-out logic. + // Percentage of screen height by sliding. + let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; + // Video shrinkage percentage. + let heightOffset = offsetPercent < this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT ? offsetPercent : + this.videoHeight - DetailConstants.MIN_VIDEO_PERCENT; + this.videoHeight = this.videoHeight - heightOffset; + } else if ((this.videoHeight < DetailConstants.MAX_VIDEO_PERCENT) && (this.relatedVideoHeight === 0) + && (offset < 0) && (CurrentOffsetUtil.scrollToTop(JSON.stringify(this.scroller.currentOffset())))) { + // Video magnification logic. + let offsetPercent = (Math.abs(offset) * DetailConstants.MAX_VIDEO_PERCENT) / this.screenHeight; + let heightOffset = offsetPercent < DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight ? offsetPercent : + DetailConstants.MAX_VIDEO_PERCENT - this.videoHeight; + this.videoHeight = this.videoHeight + heightOffset; + } else if ((offset < 0) && (this.videoHeight === DetailConstants.MAX_VIDEO_PERCENT) && + (this.relatedVideoHeight >= 0)) { + // Related list enlargement logic. + // Percentage of screen height by sliding. + let offsetPercent = (Math.abs(offset) * DetailConstants.TEN) / this.screenHeight; + this.relatedVideoHeight = (this.relatedVideoHeight + offsetPercent * DetailConstants.RELATED_LIST_HEIGHT) > + DetailConstants.RELATED_LIST_HEIGHT ? DetailConstants.RELATED_LIST_HEIGHT : (this.relatedVideoHeight + + offsetPercent * DetailConstants.RELATED_LIST_HEIGHT); + } else { + Logger.info(`No specific function`); + } + } + // Returns the actual offset 0. + return { offsetRemain: 0 }; + }) + } +} + +@Component +struct TimeText { + @Link time: string; + + build() { + Text(this.time) + .fontSize($r('app.float.time_font')) + .fontColor(Color.White) + .lineHeight($r('app.float.time_text_line')) + .width($r('app.float.time_text_width')) + } +} \ No newline at end of file diff --git a/features/videoDetail/src/main/module.json5 b/features/videoDetail/src/main/module.json5 index 41b6b59..77b0232 100644 --- a/features/videoDetail/src/main/module.json5 +++ b/features/videoDetail/src/main/module.json5 @@ -1,14 +1,11 @@ { "module": { "name": "videoDetail", - "type": "shared", - "description": "$string:shared_desc", + "type": "har", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true, - "pages": "$profile:main_pages" + ] } } \ No newline at end of file diff --git a/features/videoDetail/src/main/resources/base/element/string.json b/features/videoDetail/src/main/resources/base/element/string.json deleted file mode 100644 index 98e1d8a..0000000 --- a/features/videoDetail/src/main/resources/base/element/string.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "string": [ - { - "name": "shared_desc", - "value": "description" - } - ] -} \ No newline at end of file diff --git a/features/videoDetail/src/main/resources/base/profile/main_pages.json b/features/videoDetail/src/main/resources/base/profile/main_pages.json deleted file mode 100644 index 1898d94..0000000 --- a/features/videoDetail/src/main/resources/base/profile/main_pages.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "src": [ - "pages/Index" - ] -} diff --git a/features/videoPlayer/Index.ets b/features/videoPlayer/Index.ets index e69de29..fc4df00 100644 --- a/features/videoPlayer/Index.ets +++ b/features/videoPlayer/Index.ets @@ -0,0 +1 @@ +export { VideoPlayer } from './src/main/ets/view/VideoPlayer'; \ No newline at end of file diff --git a/features/videoPlayer/hvigorfile.ts b/features/videoPlayer/hvigorfile.ts index d993120..4218707 100644 --- a/features/videoPlayer/hvigorfile.ts +++ b/features/videoPlayer/hvigorfile.ts @@ -1,6 +1,6 @@ -import { hspTasks } from '@ohos/hvigor-ohos-plugin'; +import { harTasks } from '@ohos/hvigor-ohos-plugin'; export default { - system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ } diff --git a/features/videoPlayer/src/main/ets/pages/Index.ets b/features/videoPlayer/src/main/ets/view/VideoPlayer.ets similarity index 48% rename from features/videoPlayer/src/main/ets/pages/Index.ets rename to features/videoPlayer/src/main/ets/view/VideoPlayer.ets index 925610a..0b289fe 100644 --- a/features/videoPlayer/src/main/ets/pages/Index.ets +++ b/features/videoPlayer/src/main/ets/view/VideoPlayer.ets @@ -13,18 +13,16 @@ * limitations under the License. */ -import { display, router, window } from '@kit.ArkUI'; +import { display, window } from '@kit.ArkUI'; import { Callback, deviceInfo } from '@kit.BasicServicesKit'; -import { BreakpointConstants, CommonConstants } from '@ohos/commons'; -import { AvPlayerUtil, Logger, WindowUtil } from '@ohos/commons'; -import { FoldStateParam } from '@ohos/detail'; +import { BreakpointConstants, CommonConstants } from '@ohos/commons/'; +import { AvPlayerUtil, Logger, WindowUtil } from '@ohos/commons/'; import { PlayerConstants } from '../constants/PlayerConstants'; -import { FooterEpisodes } from '../view/FooterEpisodes'; -import { SideEpisodes } from '../view/SideEpisodes'; +import { FooterEpisodes } from './FooterEpisodes'; +import { SideEpisodes } from './SideEpisodes'; -@Entry @Component -struct Index { +export struct VideoPlayer { @StorageLink('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_LG; @StorageLink('creaseRegion') creaseRegion: number[] = []; @StorageLink('updateTime') updateTime: number = 0; @@ -32,9 +30,10 @@ struct Index { @StorageLink('totalTime') totalTime: string = CommonConstants.INITIAL_TIME; @StorageLink('progress') progress: number = 0; @StorageLink('fullScreenPlayState') fullScreenPlayState: boolean = true; + @StorageLink('isHalfFolded') isHalfFolded: boolean = false; @State isShowingSideBar: boolean = false; @State foldStatus: display.FoldStatus = display.getFoldStatus(); - @State isHalfFolded: boolean = false; + @Consume('pageInfo') pageInfo: NavPathStack; private windowUtil?: WindowUtil; private avPlayerUtil: AvPlayerUtil = new AvPlayerUtil(); private xComponentController: XComponentController = new XComponentController(); @@ -60,20 +59,6 @@ struct Index { } }; - onPageShow(): void { - try { - display.on('foldStatusChange', this.onFoldStatusChange); - } catch (exception) { - Logger.error('Failed to register callback. Code: ' + JSON.stringify(exception)); - } - this.avPlayerUtil.onTimeUpdate(); - } - - onPageHide(): void { - this.avPlayerUtil.offTimeUpdate(); - display.off('foldStatusChange'); - } - aboutToAppear() { this.windowUtil = WindowUtil.getInstance(); @@ -86,7 +71,6 @@ struct Index { this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_LANDSCAPE); } if (display.isFoldable()) { - this.isHalfFolded = (router.getParams() as FoldStateParam).isHalfFolded; if (this.isHalfFolded) { this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_LANDSCAPE); } @@ -117,142 +101,157 @@ struct Index { } build() { - Row() { - Column() { - Stack({ alignContent: Alignment.Center }) { - Flex({ - direction: FlexDirection.Column, - justifyContent: this.isHalfFolded ? FlexAlign.Start : FlexAlign.Center, - alignItems: ItemAlign.Start - }) { - Column() { - XComponent({ - id: PlayerConstants.X_COMPONENT_ID, - type: XComponentType.SURFACE, - controller: this.xComponentController - }) - .onLoad(() => { - this.xComponentController.setXComponentSurfaceSize({ - surfaceWidth: CommonConstants.X_COMPONENT_SURFACE_WIDTH, surfaceHeight: - CommonConstants.X_COMPONENT_SURFACE_HEIGHT - }); - this.surfaceId = this.xComponentController.getXComponentSurfaceId(); - this.avPlayerUtil.createAvPlayer(this.surfaceId, true); + NavDestination() { + Row() { + Column() { + Stack({ alignContent: Alignment.Center }) { + Flex({ + direction: FlexDirection.Column, + justifyContent: this.isHalfFolded ? FlexAlign.Start : FlexAlign.Center, + alignItems: ItemAlign.Start + }) { + Column() { + XComponent({ + id: PlayerConstants.X_COMPONENT_ID, + type: XComponentType.SURFACE, + controller: this.xComponentController }) - .aspectRatio(CommonConstants.VIDEO_ASPECT_RATIO) + .onLoad(() => { + this.xComponentController.setXComponentSurfaceSize({ + surfaceWidth: CommonConstants.X_COMPONENT_SURFACE_WIDTH, surfaceHeight: + CommonConstants.X_COMPONENT_SURFACE_HEIGHT + }); + this.surfaceId = this.xComponentController.getXComponentSurfaceId(); + this.avPlayerUtil.createAvPlayer(this.surfaceId, true); + }) + .aspectRatio(CommonConstants.VIDEO_ASPECT_RATIO) + } + .justifyContent(FlexAlign.Center) + .height(this.isHalfFolded ? this.creaseRegion[0] : CommonConstants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) } - .justifyContent(FlexAlign.Center) - .height(this.isHalfFolded ? this.creaseRegion[0] : CommonConstants.FULL_PERCENT) .width(CommonConstants.FULL_PERCENT) - } - .width(CommonConstants.FULL_PERCENT) - .height(CommonConstants.FULL_PERCENT) - .onClick(() => { - if (this.isShowingSideBar) { - this.isShowingSideBar = false; - } - }) - - Column() { - Row() { - TimeText({ time: $currentTime }) - .margin({ - left: $r('app.float.current_time_left'), - right: $r('app.float.current_time_right') - }) + .height(CommonConstants.FULL_PERCENT) + .onClick(() => { + if (this.isShowingSideBar) { + this.isShowingSideBar = false; + } + }) - Slider({ min: 0, max: CommonConstants.PROGRESS_HUNDRED, step: 1, value: this.progress }) - .onChange((value: number, mode: SliderChangeMode) => { - this.avPlayerUtil.sliderChange(value, mode); - }) - .layoutWeight(1) - .selectedColor($r('app.color.selected_color')) + Column() { + Row() { + TimeText({ time: $currentTime }) + .margin({ + left: $r('app.float.current_time_left'), + right: $r('app.float.current_time_right') + }) - TimeText({ time: $totalTime }) - .margin({ - left: $r('app.float.total_time_left'), - right: $r('app.float.total_time_right') - }) - } - .width(CommonConstants.FULL_PERCENT) - .height($r('app.float.time_row_height')) - .alignItems(VerticalAlign.Center) + Slider({ min: 0, max: CommonConstants.PROGRESS_HUNDRED, step: 1, value: this.progress }) + .onChange((value: number, mode: SliderChangeMode) => { + this.avPlayerUtil.sliderChange(value, mode); + }) + .layoutWeight(1) + .selectedColor($r('app.color.selected_color')) - Row() { - Row() { - Image(this.fullScreenPlayState ? $r('app.media.ic_public_pause') : $r('app.media.ic_public_play')) - .height($r('app.float.icon_size')) - .width($r('app.float.icon_size')) - .margin({ left: $r('app.float.icon_margin') }) - .onClick(() => { - this.avPlayerUtil.playerStateControl(); + TimeText({ time: $totalTime }) + .margin({ + left: $r('app.float.total_time_left'), + right: $r('app.float.total_time_right') }) - ImgIcon({ img: $r('app.media.ic_public_play_next') }) - ImgIcon({ img: $r('app.media.ic_public_view_list_white') }) } - .margin({ - top: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? '0' : $r('app.float.icon_row_top'), + .width(CommonConstants.FULL_PERCENT) + .height($r('app.float.time_row_height')) + .alignItems(VerticalAlign.Center) + + Row() { + Row() { + Image(this.fullScreenPlayState ? $r('app.media.ic_public_pause') : $r('app.media.ic_public_play')) + .height($r('app.float.icon_size')) + .width($r('app.float.icon_size')) + .margin({ left: $r('app.float.icon_margin') }) + .onClick(() => { + this.avPlayerUtil.playerStateControl(); + }) + ImgIcon({ img: $r('app.media.ic_public_play_next') }) + ImgIcon({ img: $r('app.media.ic_public_view_list_white') }) + } + .margin({ + top: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? '0' : $r('app.float.icon_row_top'), bottom: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? $r('app.float.icon_row_bottom_sm') : $r('app.float.icon_row_bottom') - }) + }) - Blank() + Blank() - Row() { - TextButton({ content: PlayerConstants.PLAYER_TEXT_LIST[0] }) - .onClick(() => { - this.isShowingSideBar = !this.isShowingSideBar; - }) - TextButton({ content: PlayerConstants.PLAYER_TEXT_LIST[2] }) - TextButton({ content: PlayerConstants.PLAYER_TEXT_LIST[3] }) - } - .margin({ - top: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? $r('app.float.button_row_top_sm') : + Row() { + TextButton({ content: PlayerConstants.PLAYER_TEXT_LIST[0] }) + .onClick(() => { + this.isShowingSideBar = !this.isShowingSideBar; + }) + TextButton({ content: PlayerConstants.PLAYER_TEXT_LIST[2] }) + TextButton({ content: PlayerConstants.PLAYER_TEXT_LIST[3] }) + } + .margin({ + top: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? $r('app.float.button_row_top_sm') : $r('app.float.button_row_top'), - bottom: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? + bottom: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? $r('app.float.button_row_bottom_sm') : $r('app.float.button_row_bottom') - }) + }) + } + .height($r('app.float.icon_button_row_height')) + .width(CommonConstants.FULL_PERCENT) } - .height($r('app.float.icon_button_row_height')) + .height(CommonConstants.FULL_PERCENT) .width(CommonConstants.FULL_PERCENT) + .justifyContent(FlexAlign.End) + .visibility(this.isShowingSideBar ? Visibility.None : Visibility.Visible) + + Image($r('app.media.ic_public_back')) + .height($r('app.float.icon_size')) + .width($r('app.float.icon_size')) + .position({ + x: $r('app.float.back_position_x'), + y: this.isHalfFolded ? this.creaseRegion[0] + this.creaseRegion[1] : $r('app.float.back_position_y') + }) + .fillColor(Color.White) + .onClick(() => { + this.pageInfo.pop(); + }) + .visibility(!this.isShowingSideBar? Visibility.Visible : Visibility.None) } - .height(CommonConstants.FULL_PERCENT) .width(CommonConstants.FULL_PERCENT) - .justifyContent(FlexAlign.End) - .visibility(this.isShowingSideBar ? Visibility.None : Visibility.Visible) + .height(this.isShowingSideBar ? this.creaseRegion[0] : CommonConstants.FULL_PERCENT) + .layoutWeight(this.isHalfFolded? 0 : 1) - Image($r('app.media.ic_public_back')) - .height($r('app.float.icon_size')) - .width($r('app.float.icon_size')) - .position({ - x: $r('app.float.back_position_x'), - y: this.isHalfFolded ? this.creaseRegion[0] + this.creaseRegion[1] : $r('app.float.back_position_y') - }) - .fillColor(Color.White) - .onClick(() => { - router.back(); - }) - .visibility(!this.isShowingSideBar? Visibility.Visible : Visibility.None) - } - .width(CommonConstants.FULL_PERCENT) - .height(this.isShowingSideBar ? this.creaseRegion[0] : CommonConstants.FULL_PERCENT) - .layoutWeight(this.isHalfFolded? 0 : 1) + Blank() + .height(this.creaseRegion[1]) + .width(CommonConstants.FULL_PERCENT) + .visibility(this.isHalfFolded && this.isShowingSideBar ? Visibility.Visible : Visibility.None) - Blank() - .height(this.creaseRegion[1]) - .width(CommonConstants.FULL_PERCENT) - .visibility(this.isHalfFolded && this.isShowingSideBar ? Visibility.Visible : Visibility.None) + FooterEpisodes({ isShowingSideBar: $isShowingSideBar, foldStatus: this.foldStatus }) + } + .layoutWeight(3) - FooterEpisodes({ isShowingSideBar: $isShowingSideBar, foldStatus: this.foldStatus }) + SideEpisodes({ isShowingSideBar: $isShowingSideBar, foldStatus: this.foldStatus }) } - .layoutWeight(3) - - SideEpisodes({ isShowingSideBar: $isShowingSideBar, foldStatus: this.foldStatus }) + .justifyContent(FlexAlign.Start) + .backgroundColor(Color.Black) + .height(CommonConstants.FULL_PERCENT) + .width(CommonConstants.FULL_PERCENT) } - .justifyContent(FlexAlign.Start) - .backgroundColor(Color.Black) - .height(CommonConstants.FULL_PERCENT) - .width(CommonConstants.FULL_PERCENT) + .hideTitleBar(true) + .onShown(() => { + try { + display.on('foldStatusChange', this.onFoldStatusChange); + } catch (exception) { + Logger.error('Failed to register callback. Code: ' + JSON.stringify(exception)); + } + this.avPlayerUtil.onTimeUpdate(); + }) + .onHidden(() => { + this.avPlayerUtil.offTimeUpdate(); + display.off('foldStatusChange'); + }) } } diff --git a/features/videoPlayer/src/main/module.json5 b/features/videoPlayer/src/main/module.json5 index b195a21..e663fce 100644 --- a/features/videoPlayer/src/main/module.json5 +++ b/features/videoPlayer/src/main/module.json5 @@ -1,14 +1,11 @@ { "module": { "name": "videoPlayer", - "type": "shared", - "description": "$string:shared_desc", + "type": "har", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true, - "pages": "$profile:main_pages" + ] } } \ No newline at end of file diff --git a/features/videoPlayer/src/main/resources/base/element/string.json b/features/videoPlayer/src/main/resources/base/element/string.json deleted file mode 100644 index 98e1d8a..0000000 --- a/features/videoPlayer/src/main/resources/base/element/string.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "string": [ - { - "name": "shared_desc", - "value": "description" - } - ] -} \ No newline at end of file diff --git a/features/videoPlayer/src/main/resources/base/profile/main_pages.json b/features/videoPlayer/src/main/resources/base/profile/main_pages.json deleted file mode 100644 index 1898d94..0000000 --- a/features/videoPlayer/src/main/resources/base/profile/main_pages.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "src": [ - "pages/Index" - ] -} diff --git a/products/phone/oh-package.json5 b/products/phone/oh-package.json5 index 9981d61..bb69c54 100644 --- a/products/phone/oh-package.json5 +++ b/products/phone/oh-package.json5 @@ -10,6 +10,7 @@ "dependencies": { "@ohos/commons": "file:../../commons/base", "@ohos/videoDetail": "file:../../features/videoDetail", - "@ohos/home": "file:../../features/home" + "@ohos/home": "file:../../features/home", + "@ohos/videoPlayer": "file:../../features/videoPlayer" } } \ No newline at end of file diff --git a/products/phone/src/main/ets/entryability/EntryAbility.ets b/products/phone/src/main/ets/entryability/EntryAbility.ets index 17e3b22..3b4bbdf 100644 --- a/products/phone/src/main/ets/entryability/EntryAbility.ets +++ b/products/phone/src/main/ets/entryability/EntryAbility.ets @@ -41,7 +41,7 @@ export default class EntryAbility extends UIAbility { }) }) - let windowUtil = WindowUtil.getInstance(); + let windowUtil: WindowUtil | undefined = WindowUtil.getInstance(); if (windowUtil !== undefined) { windowUtil.setWindowStage(windowStage); windowUtil.setMainWindowPortrait(); diff --git a/products/phone/src/main/ets/pages/Index.ets b/products/phone/src/main/ets/pages/Index.ets index 3bddf43..a54c27b 100644 --- a/products/phone/src/main/ets/pages/Index.ets +++ b/products/phone/src/main/ets/pages/Index.ets @@ -14,15 +14,41 @@ */ import { Home } from '@ohos/home'; -import { CommonConstants } from '@ohos/commons'; +import { CommonConstants, WindowUtil } from '@ohos/commons'; +import { VideoDetail } from '@ohos/videoDetail/src/main/ets/view/VideoDetail'; +import { VideoPlayer } from '@ohos/videoPlayer/Index'; @Entry @Component struct Index { + @Provide('pageInfo') pageInfo: NavPathStack = new NavPathStack(); + + aboutToDisappear(): void { + let windowUtil: WindowUtil | undefined = WindowUtil.getInstance(); + if (windowUtil === undefined) { + return; + } + windowUtil.offWindowSizeChange(); + } + + @Builder + PageMap(name: string) { + if (name === 'VideoDetail') { + VideoDetail() + } else if (name === 'VideoPlayer') { + VideoPlayer() + } + } + build() { - Column() { + Navigation(this.pageInfo) { Home() } + .mode(NavigationMode.Stack) + .navDestination(this.PageMap) + .hideToolBar(true) + .hideTitleBar(true) + .hideBackButton(true) .width(CommonConstants.FULL_PERCENT) .height(CommonConstants.FULL_PERCENT) } diff --git a/screenshots/device/config.png b/screenshots/device/config.png deleted file mode 100644 index cf40268303f270370cbccd9dadf51dc36f250fc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37380 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 PcbURnRheAGlh^+P&brSc diff --git a/screenshots/device/run.png b/screenshots/device/run.png deleted file mode 100644 index 7655fa7e041bb067e028029d820bd2d320e2cd83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`OFUg1Lo9le|9p9Qxt@)SL0EOx zMk#}@XPDZ|@81*5W#Ha*U}^Yu$#whp9)7Sc<@|$%PYxV7b;fHJw*(N>{r`J*!_#ka zZEc5Zd8Wt5s^4XhsQCO=_V5&A?hjSmhq-Ss*yRh#a_`vVT4*Bll$8w#!qURl#3`I& zur>5;E6}xP6Vy|@6r*rR^@za2r^gp)FY65E4P!2_oUXzA!BSj0LFU694u-Ouw&(3$ S)#L!(%i!ti=d#Wzp$P!&;!{xo -- Gitee